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>
14237 lines
529 KiB
Go
14237 lines
529 KiB
Go
// Code generated by modernc.org/undup from the per-target sqlite_*.go files; DO NOT EDIT.
|
|
|
|
//go:build (darwin && amd64) || (darwin && arm64) || (freebsd && 386) || (freebsd && amd64) || (freebsd && arm) || (freebsd && arm64) || (linux && 386) || (linux && amd64) || (linux && arm) || (linux && arm64) || (linux && loong64) || (linux && ppc64le) || (linux && riscv64) || (linux && s390x) || (netbsd && amd64) || (openbsd && amd64) || (openbsd && arm64)
|
|
|
|
package sqlite3
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"modernc.org/libc"
|
|
)
|
|
|
|
const BIG_ENDIAN = 4321
|
|
|
|
const BUFSIZ = 1024
|
|
|
|
const DOTLOCK_SUFFIX = ".lock"
|
|
|
|
type DbPath = TDbPath
|
|
|
|
type Dl_info = TDl_info
|
|
|
|
const ENOTBLK = 15
|
|
|
|
const ETXTBSY = 26
|
|
|
|
const FD_CLOEXEC = 1
|
|
|
|
const F_DUPFD = 0
|
|
|
|
const F_GETFD = 1
|
|
|
|
const F_GETFL = 3
|
|
|
|
const F_LOCK = 1
|
|
|
|
const F_OK = 0
|
|
|
|
const F_SETFD = 2
|
|
|
|
const F_SETFL = 4
|
|
|
|
const F_TEST = 3
|
|
|
|
const F_TLOCK = 2
|
|
|
|
const F_ULOCK = 0
|
|
|
|
const F_UNLCK = 2
|
|
|
|
const HAVE_FCHMOD = 1
|
|
|
|
const HAVE_GETHOSTUUID = 0
|
|
|
|
const INTERFACE = 1
|
|
|
|
const ITIMER_PROF = 2
|
|
|
|
const ITIMER_REAL = 0
|
|
|
|
const ITIMER_VIRTUAL = 1
|
|
|
|
const LITTLE_ENDIAN = 1234
|
|
|
|
const L_INCR = 1
|
|
|
|
const L_SET = 0
|
|
|
|
const L_XTND = 2
|
|
|
|
const MADV_DONTNEED = 4
|
|
|
|
const MADV_NORMAL = 0
|
|
|
|
const MADV_RANDOM = 1
|
|
|
|
const MADV_SEQUENTIAL = 2
|
|
|
|
const MADV_WILLNEED = 3
|
|
|
|
const MAP_FAILED = -1
|
|
|
|
const MAP_FILE = 0
|
|
|
|
const MAP_FIXED = 16
|
|
|
|
const MAP_PRIVATE = 2
|
|
|
|
const MAP_SHARED = 1
|
|
|
|
const MATH_ERREXCEPT = 2
|
|
|
|
const MATH_ERRNO = 1
|
|
|
|
const MAX_PATHNAME = 512
|
|
|
|
const MS_ASYNC = 1
|
|
|
|
const O_BINARY = 0
|
|
|
|
const O_RDONLY = 0
|
|
|
|
const O_RDWR = 2
|
|
|
|
const O_WRONLY = 1
|
|
|
|
const PDP_ENDIAN = 3412
|
|
|
|
const POSIX_MADV_DONTNEED = 4
|
|
|
|
const POSIX_MADV_NORMAL = 0
|
|
|
|
const POSIX_MADV_RANDOM = 1
|
|
|
|
const POSIX_MADV_SEQUENTIAL = 2
|
|
|
|
const POSIX_MADV_WILLNEED = 3
|
|
|
|
const PROT_EXEC = 4
|
|
|
|
const PROT_NONE = 0
|
|
|
|
const PROT_READ = 1
|
|
|
|
const PROT_WRITE = 2
|
|
|
|
const RAND_MAX = 2147483647
|
|
|
|
const RTLD_LAZY = 1
|
|
|
|
const RTLD_NEXT = -1
|
|
|
|
const RTLD_NOW = 2
|
|
|
|
const R_OK = 4
|
|
|
|
const SQLITE_DEFAULT_FILE_PERMISSIONS = 420
|
|
|
|
const SQLITE_DEFAULT_PROXYDIR_PERMISSIONS = 493
|
|
|
|
const SQLITE_FSFLAGS_IS_MSDOS = 1
|
|
|
|
const SQLITE_MAX_SYMLINKS = 100
|
|
|
|
const SQLITE_MINIMUM_FILE_DESCRIPTOR = 3
|
|
|
|
const SQLITE_OS_UNIX = 1
|
|
|
|
const S_IEXEC = 64
|
|
|
|
const S_IFBLK = 24576
|
|
|
|
const S_IFCHR = 8192
|
|
|
|
const S_IFDIR = 16384
|
|
|
|
const S_IFIFO = 4096
|
|
|
|
const S_IFLNK = 40960
|
|
|
|
const S_IFMT = 61440
|
|
|
|
const S_IFREG = 32768
|
|
|
|
const S_IFSOCK = 49152
|
|
|
|
const S_IREAD = 256
|
|
|
|
const S_IRGRP = 32
|
|
|
|
const S_IROTH = 4
|
|
|
|
const S_IRUSR = 256
|
|
|
|
const S_IRWXG = 56
|
|
|
|
const S_IRWXO = 7
|
|
|
|
const S_IRWXU = 448
|
|
|
|
const S_ISGID = 1024
|
|
|
|
const S_ISUID = 2048
|
|
|
|
const S_ISVTX = 512
|
|
|
|
const S_IWGRP = 16
|
|
|
|
const S_IWOTH = 2
|
|
|
|
const S_IWRITE = 128
|
|
|
|
const S_IWUSR = 128
|
|
|
|
const S_IXGRP = 8
|
|
|
|
const S_IXOTH = 1
|
|
|
|
const S_IXUSR = 64
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** A pathname under construction
|
|
// */
|
|
type TDbPath = struct {
|
|
Frc int32
|
|
FnSymlink int32
|
|
FzOut uintptr
|
|
FnOut int32
|
|
FnUsed int32
|
|
}
|
|
|
|
type TDl_info = struct {
|
|
Fdli_fname uintptr
|
|
Fdli_fbase uintptr
|
|
Fdli_sname uintptr
|
|
Fdli_saddr uintptr
|
|
}
|
|
|
|
const TIME_UTC = 1
|
|
|
|
const TIOCM_CAR = 64
|
|
|
|
const TIOCM_CD = 64
|
|
|
|
const TIOCM_CTS = 32
|
|
|
|
const TIOCM_DSR = 256
|
|
|
|
const TIOCM_DTR = 2
|
|
|
|
const TIOCM_LE = 1
|
|
|
|
const TIOCM_RI = 128
|
|
|
|
const TIOCM_RNG = 128
|
|
|
|
const TIOCM_RTS = 4
|
|
|
|
const TIOCM_SR = 16
|
|
|
|
const TIOCM_ST = 8
|
|
|
|
const TIOCPKT_DATA = 0
|
|
|
|
const TIOCPKT_DOSTOP = 32
|
|
|
|
const TIOCPKT_FLUSHREAD = 1
|
|
|
|
const TIOCPKT_FLUSHWRITE = 2
|
|
|
|
const TIOCPKT_IOCTL = 64
|
|
|
|
const TIOCPKT_NOSTOP = 16
|
|
|
|
const TIOCPKT_START = 8
|
|
|
|
const TIOCPKT_STOP = 4
|
|
|
|
/* An i-node */
|
|
type TUnixUnusedFd = struct {
|
|
Ffd int32
|
|
Fflags int32
|
|
FpNext uintptr
|
|
}
|
|
|
|
type Tblkcnt_t = int64
|
|
|
|
type Tcaddr_t = uintptr
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** An abstract type for a pointer to an IO method finder function:
|
|
// */
|
|
type Tfinder_type = uintptr
|
|
|
|
type Tgid_t = uint32
|
|
|
|
type Tino_t = uint64
|
|
|
|
type Tquad_t = int64
|
|
|
|
type Tu_int16_t = uint16
|
|
|
|
type Tu_int32_t = uint32
|
|
|
|
type Tu_int64_t = uint64
|
|
|
|
type Tu_int8_t = uint8
|
|
|
|
type Tu_quad_t = uint64
|
|
|
|
type Tuid_t = uint32
|
|
|
|
type Tuint = uint32
|
|
|
|
// C documentation
|
|
//
|
|
// /* Forward references */
|
|
type TunixShm = struct {
|
|
FpShmNode uintptr
|
|
FpNext uintptr
|
|
FhasMutex Tu8
|
|
Fid Tu8
|
|
FsharedMask Tu16
|
|
FexclMask Tu16
|
|
}
|
|
|
|
/* Connection shared memory */
|
|
type TunixShmNode = struct {
|
|
FpInode uintptr
|
|
FpShmMutex uintptr
|
|
FzFilename uintptr
|
|
FhShm int32
|
|
FszRegion int32
|
|
FnRegion Tu16
|
|
FisReadonly Tu8
|
|
FisUnlocked Tu8
|
|
FapRegion uintptr
|
|
FnRef int32
|
|
FpFirst uintptr
|
|
FaLock [8]int32
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Many system calls are accessed through pointer-to-functions so that
|
|
// ** they may be overridden at runtime to facilitate fault injection during
|
|
// ** testing and sandboxing. The following array holds the names and pointers
|
|
// ** to all overrideable system calls.
|
|
// */
|
|
type Tunix_syscall = struct {
|
|
FzName uintptr
|
|
FpCurrent Tsqlite3_syscall_ptr
|
|
FpDefault Tsqlite3_syscall_ptr
|
|
}
|
|
|
|
type Tushort = uint16
|
|
|
|
/******************************************************************************
|
|
****************** Begin Unique File ID Utility Used By VxWorks ***************
|
|
**
|
|
** On most versions of unix, we can get a unique ID for a file by concatenating
|
|
** the device number and the inode number. But this does not work on VxWorks.
|
|
** On VxWorks, a unique file id must be based on the canonical filename.
|
|
**
|
|
** A pointer to an instance of the following structure can be used as a
|
|
** unique file ID in VxWorks. Each instance of this structure contains
|
|
** a copy of the canonical filename. There is also a reference count.
|
|
** The structure is reclaimed when the number of pointers to it drops to
|
|
** zero.
|
|
**
|
|
** There are never very many files open at one time and lookups are not
|
|
** a performance-critical path, so it is sufficient to put these
|
|
** structures on a linked list.
|
|
*/
|
|
type TvxworksFileId = struct {
|
|
FpNext uintptr
|
|
FnRef int32
|
|
FnName int32
|
|
FzCanonicalName uintptr
|
|
}
|
|
|
|
type Twinsize = struct {
|
|
Fws_row uint16
|
|
Fws_col uint16
|
|
Fws_xpixel uint16
|
|
Fws_ypixel uint16
|
|
}
|
|
|
|
const UNIXFILE_DELETE = 32
|
|
|
|
const UNIXFILE_DIRSYNC = 8
|
|
|
|
const UNIXFILE_EXCL = 1
|
|
|
|
const UNIXFILE_NOLOCK = 128
|
|
|
|
const UNIXFILE_PERSIST_WAL = 4
|
|
|
|
const UNIXFILE_PSOW = 16
|
|
|
|
const UNIXFILE_RDONLY = 2
|
|
|
|
const UNIXFILE_URI = 64
|
|
|
|
const UNIX_SHM_BASE = 120
|
|
|
|
const UNIX_SHM_DMS = 128
|
|
|
|
type UnixUnusedFd = TUnixUnusedFd
|
|
|
|
const W_OK = 2
|
|
|
|
const X_OK = 1
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate or return the aggregate context for a user function. A new
|
|
// ** context is allocated on the first call. Subsequent calls return the
|
|
// ** same context that was returned on prior calls.
|
|
// */
|
|
func Xsqlite3_aggregate_context(tls *libc.TLS, p uintptr, nByte int32) (r uintptr) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer((*Tsqlite3_context)(unsafe.Pointer(p)).FpMem)).Fflags)&int32(MEM_Agg) == 0 {
|
|
return _createAggContext(tls, p, nByte)
|
|
} else {
|
|
return (*TMem)(unsafe.Pointer((*Tsqlite3_context)(unsafe.Pointer(p)).FpMem)).Fz
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the total number of pages in the source database as of the most
|
|
// ** recent call to sqlite3_backup_step().
|
|
// */
|
|
func Xsqlite3_backup_pagecount(tls *libc.TLS, p uintptr) (r int32) {
|
|
return libc.Int32FromUint32((*Tsqlite3_backup)(unsafe.Pointer(p)).FnPagecount)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the number of pages still to be backed up as of the most recent
|
|
// ** call to sqlite3_backup_step().
|
|
// */
|
|
func Xsqlite3_backup_remaining(tls *libc.TLS, p uintptr) (r int32) {
|
|
return libc.Int32FromUint32((*Tsqlite3_backup)(unsafe.Pointer(p)).FnRemaining)
|
|
}
|
|
|
|
func Xsqlite3_bind_blob64(tls *libc.TLS, pStmt uintptr, i int32, zData uintptr, nData Tsqlite3_uint64, __ccgo_fp_xDel uintptr) (r int32) {
|
|
return _bindText(tls, pStmt, i, zData, libc.Int64FromUint64(nData), __ccgo_fp_xDel, uint8(0))
|
|
}
|
|
|
|
func Xsqlite3_bind_null(tls *libc.TLS, pStmt uintptr, i 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 */
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fmutex)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func Xsqlite3_bind_value(tls *libc.TLS, pStmt uintptr, i int32, pValue uintptr) (r int32) {
|
|
var rc int32
|
|
var v1 float64
|
|
_, _ = rc, v1
|
|
switch Xsqlite3_value_type(tls, pValue) {
|
|
case int32(SQLITE_INTEGER):
|
|
rc = Xsqlite3_bind_int64(tls, pStmt, i, *(*Ti64)(unsafe.Pointer(pValue)))
|
|
case int32(SQLITE_FLOAT):
|
|
if libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pValue)).Fflags)&int32(MEM_Real) != 0 {
|
|
v1 = *(*float64)(unsafe.Pointer(pValue))
|
|
} else {
|
|
v1 = float64(*(*Ti64)(unsafe.Pointer(pValue)))
|
|
}
|
|
rc = Xsqlite3_bind_double(tls, pStmt, i, v1)
|
|
case int32(SQLITE_BLOB):
|
|
if libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pValue)).Fflags)&int32(MEM_Zero) != 0 {
|
|
rc = Xsqlite3_bind_zeroblob(tls, pStmt, i, *(*int32)(unsafe.Pointer(&(*Tsqlite3_value)(unsafe.Pointer(pValue)).Fu)))
|
|
} else {
|
|
rc = Xsqlite3_bind_blob(tls, pStmt, i, (*Tsqlite3_value)(unsafe.Pointer(pValue)).Fz, (*Tsqlite3_value)(unsafe.Pointer(pValue)).Fn, uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
case int32(SQLITE_TEXT):
|
|
rc = _bindText(tls, pStmt, i, (*Tsqlite3_value)(unsafe.Pointer(pValue)).Fz, int64((*Tsqlite3_value)(unsafe.Pointer(pValue)).Fn), uintptr(-libc.Int32FromInt32(1)), (*Tsqlite3_value)(unsafe.Pointer(pValue)).Fenc)
|
|
default:
|
|
rc = Xsqlite3_bind_null(tls, pStmt, i)
|
|
break
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the number of columns in the result set for the statement pStmt.
|
|
// */
|
|
func Xsqlite3_column_count(tls *libc.TLS, pStmt uintptr) (r int32) {
|
|
var pVm uintptr
|
|
_ = pVm
|
|
pVm = pStmt
|
|
if pVm == uintptr(0) {
|
|
return 0
|
|
}
|
|
return libc.Int32FromUint16((*TVdbe)(unsafe.Pointer(pVm)).FnResColumn)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Register a new collation sequence with the database handle db.
|
|
// */
|
|
func Xsqlite3_create_collation_v2(tls *libc.TLS, db uintptr, zName uintptr, enc int32, pCtx uintptr, __ccgo_fp_xCompare uintptr, __ccgo_fp_xDel uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
rc = _createCollation(tls, db, zName, libc.Uint8FromInt32(enc), pCtx, __ccgo_fp_xCompare, __ccgo_fp_xDel)
|
|
rc = _sqlite3ApiExit(tls, db, rc)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the number of values available from the current row of the
|
|
// ** currently executing statement pStmt.
|
|
// */
|
|
func Xsqlite3_data_count(tls *libc.TLS, pStmt uintptr) (r int32) {
|
|
var pVm uintptr
|
|
_ = pVm
|
|
pVm = pStmt
|
|
if pVm == uintptr(0) || (*TVdbe)(unsafe.Pointer(pVm)).FpResultRow == uintptr(0) {
|
|
return 0
|
|
}
|
|
return libc.Int32FromUint16((*TVdbe)(unsafe.Pointer(pVm)).FnResColumn)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Enable or disable the extended result codes.
|
|
// */
|
|
func Xsqlite3_extended_result_codes(tls *libc.TLS, db uintptr, onoff int32) (r int32) {
|
|
var v1 uint32
|
|
_ = v1
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
if onoff != 0 {
|
|
v1 = uint32(0xffffffff)
|
|
} else {
|
|
v1 = uint32(0xff)
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FerrMask = libc.Int32FromUint32(v1)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Test to see whether or not the database connection is in autocommit
|
|
// ** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on
|
|
// ** by default. Autocommit is disabled by a BEGIN statement and reenabled
|
|
// ** by the next COMMIT or ROLLBACK.
|
|
// */
|
|
func Xsqlite3_get_autocommit(tls *libc.TLS, db uintptr) (r int32) {
|
|
var iRet int32
|
|
_ = iRet
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
iRet = libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FautoCommit)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return iRet
|
|
}
|
|
|
|
func Xsqlite3_keyword_name(tls *libc.TLS, i int32, pzName uintptr, pnName uintptr) (r int32) {
|
|
if i < 0 || i >= int32(SQLITE_N_KEYWORD) {
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
i = i + 1
|
|
**(**uintptr)(__ccgo_up(pzName)) = uintptr(unsafe.Pointer(&_zKWText)) + uintptr(_aKWOffset[i])
|
|
**(**int32)(__ccgo_up(pnName)) = libc.Int32FromUint8(_aKWLen[i])
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This version of the memory allocation is for use by the application.
|
|
// ** First make sure the memory subsystem is initialized, then do the
|
|
// ** allocation.
|
|
// */
|
|
func Xsqlite3_malloc(tls *libc.TLS, n int32) (r uintptr) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if Xsqlite3_initialize(tls) != 0 {
|
|
return uintptr(0)
|
|
}
|
|
if n <= 0 {
|
|
v1 = uintptr(0)
|
|
} else {
|
|
v1 = _sqlite3Malloc(tls, libc.Uint64FromInt32(n))
|
|
}
|
|
return v1
|
|
}
|
|
|
|
func Xsqlite3_msize(tls *libc.TLS, p uintptr) (r Tsqlite3_uint64) {
|
|
var v1 int32
|
|
_ = v1
|
|
if p != 0 {
|
|
v1 = (*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fm.FxSize})))(tls, p)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
return libc.Uint64FromInt32(v1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Open a new database handle.
|
|
// */
|
|
func Xsqlite3_open(tls *libc.TLS, zFilename uintptr, ppDb uintptr) (r int32) {
|
|
return _openDatabase(tls, zFilename, ppDb, libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_OPEN_READWRITE)|libc.Int32FromInt32(SQLITE_OPEN_CREATE)), uintptr(0))
|
|
}
|
|
|
|
func Xsqlite3_open_v2(tls *libc.TLS, filename uintptr, ppDb uintptr, flags int32, zVfs uintptr) (r int32) {
|
|
return _openDatabase(tls, filename, ppDb, libc.Uint32FromInt32(flags), zVfs)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Shutdown the operating system interface.
|
|
// **
|
|
// ** Some operating systems might need to do some cleanup in this routine,
|
|
// ** to release dynamically allocated objects. But not on unix.
|
|
// ** This routine is a no-op for unix.
|
|
// */
|
|
func Xsqlite3_os_end(tls *libc.TLS) (r int32) {
|
|
_unixBigLock = uintptr(0)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
/************** End of os_unix.c *********************************************/
|
|
/************** Begin file os_win.c ******************************************/
|
|
/*
|
|
** 2004 May 22
|
|
**
|
|
** 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 that is specific to Windows.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
/************** End of os_win.c **********************************************/
|
|
/************** Begin file memdb.c *******************************************/
|
|
/*
|
|
** 2016-09-07
|
|
**
|
|
** 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 an in-memory VFS. A database is held as a contiguous
|
|
** block of memory.
|
|
**
|
|
** This file also implements interface sqlite3_serialize() and
|
|
** sqlite3_deserialize().
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called from within a pre-update callback to retrieve
|
|
// ** the number of columns in the row being updated, deleted or inserted.
|
|
// */
|
|
func Xsqlite3_preupdate_count(tls *libc.TLS, db uintptr) (r int32) {
|
|
var p uintptr
|
|
var v1 int32
|
|
_, _ = p, v1
|
|
p = (*Tsqlite3)(unsafe.Pointer(db)).FpPreUpdate
|
|
if p != 0 {
|
|
v1 = libc.Int32FromUint16((*TKeyInfo)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpKeyinfo)).FnKeyField)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine sets the progress callback for an Sqlite database to the
|
|
// ** given callback function with the given argument. The progress callback will
|
|
// ** be invoked every nOps opcodes.
|
|
// */
|
|
func Xsqlite3_progress_handler(tls *libc.TLS, db uintptr, nOps int32, __ccgo_fp_xProgress uintptr, pArg uintptr) {
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
if nOps > 0 {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FxProgress = __ccgo_fp_xProgress
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnProgressOps = libc.Uint32FromInt32(nOps)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpProgressArg = pArg
|
|
} else {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FxProgress = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnProgressOps = uint32(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpProgressArg = uintptr(0)
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The public interface to sqlite3Realloc. Make sure that the memory
|
|
// ** subsystem is initialized prior to invoking sqliteRealloc.
|
|
// */
|
|
func Xsqlite3_realloc(tls *libc.TLS, pOld uintptr, n int32) (r uintptr) {
|
|
if Xsqlite3_initialize(tls) != 0 {
|
|
return uintptr(0)
|
|
}
|
|
if n < 0 {
|
|
n = 0
|
|
} /* IMP: R-26507-47431 */
|
|
return _sqlite3Realloc(tls, pOld, libc.Uint64FromInt32(n))
|
|
}
|
|
|
|
func Xsqlite3_result_blob64(tls *libc.TLS, pCtx uintptr, z uintptr, n Tsqlite3_uint64, __ccgo_fp_xDel uintptr) {
|
|
if n > uint64(0x7fffffff) {
|
|
_invokeValueDestructor(tls, z, __ccgo_fp_xDel, pCtx)
|
|
} else {
|
|
_setResultStrOrError(tls, pCtx, z, libc.Int32FromUint64(n), uint8(0), __ccgo_fp_xDel)
|
|
}
|
|
}
|
|
|
|
func Xsqlite3_result_error_code(tls *libc.TLS, pCtx uintptr, errCode int32) {
|
|
var v1 int32
|
|
_ = v1
|
|
if errCode != 0 {
|
|
v1 = errCode
|
|
} else {
|
|
v1 = -int32(1)
|
|
}
|
|
(*Tsqlite3_context)(unsafe.Pointer(pCtx)).FisError = v1
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer((*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut)).Fflags)&int32(MEM_Null) != 0 {
|
|
_setResultStrOrError(tls, pCtx, _sqlite3ErrStr(tls, errCode), -int32(1), uint8(SQLITE_UTF8), libc.UintptrFromInt32(0))
|
|
}
|
|
}
|
|
|
|
func Xsqlite3_result_text16be(tls *libc.TLS, pCtx uintptr, z uintptr, n int32, __ccgo_fp_xDel uintptr) {
|
|
_setResultStrOrError(tls, pCtx, z, libc.Int32FromUint64(libc.Uint64FromInt32(n) & ^libc.Uint64FromInt32(1)), uint8(SQLITE_UTF16BE), __ccgo_fp_xDel)
|
|
}
|
|
|
|
func Xsqlite3_result_text16le(tls *libc.TLS, pCtx uintptr, z uintptr, n int32, __ccgo_fp_xDel uintptr) {
|
|
_setResultStrOrError(tls, pCtx, z, libc.Int32FromUint64(libc.Uint64FromInt32(n) & ^libc.Uint64FromInt32(1)), uint8(SQLITE_UTF16LE), __ccgo_fp_xDel)
|
|
}
|
|
|
|
func Xsqlite3_result_value(tls *libc.TLS, pCtx uintptr, pValue uintptr) {
|
|
var pOut uintptr
|
|
_ = pOut
|
|
pOut = (*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut
|
|
_sqlite3VdbeMemCopy(tls, pOut, pValue)
|
|
_sqlite3VdbeChangeEncoding(tls, pOut, libc.Int32FromUint8((*Tsqlite3_context)(unsafe.Pointer(pCtx)).Fenc))
|
|
if _sqlite3VdbeMemTooBig(tls, pOut) != 0 {
|
|
Xsqlite3_result_error_toobig(tls, pCtx)
|
|
}
|
|
}
|
|
|
|
func Xsqlite3_result_zeroblob(tls *libc.TLS, pCtx uintptr, n int32) {
|
|
var v1 int32
|
|
_ = v1
|
|
if n > 0 {
|
|
v1 = n
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
Xsqlite3_result_zeroblob64(tls, pCtx, libc.Uint64FromInt32(v1))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the prepared statement is in need of being reset.
|
|
// */
|
|
func Xsqlite3_stmt_busy(tls *libc.TLS, pStmt uintptr) (r int32) {
|
|
var v uintptr
|
|
_ = v
|
|
v = pStmt
|
|
return libc.BoolInt32(v != uintptr(0) && libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(v)).FeVdbeState) == int32(VDBE_RUN_STATE))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Return any error code associated with p */
|
|
func Xsqlite3_str_errcode(tls *libc.TLS, p uintptr) (r int32) {
|
|
var v1 int32
|
|
_ = v1
|
|
if p != 0 {
|
|
v1 = libc.Int32FromUint8((*Tsqlite3_str)(unsafe.Pointer(p)).FaccError)
|
|
} else {
|
|
v1 = int32(SQLITE_NOMEM)
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Return the current length of p in bytes */
|
|
func Xsqlite3_str_length(tls *libc.TLS, p uintptr) (r int32) {
|
|
var v1 uint32
|
|
_ = v1
|
|
if p != 0 {
|
|
v1 = (*Tsqlite3_str)(unsafe.Pointer(p)).FnChar
|
|
} else {
|
|
v1 = uint32(0)
|
|
}
|
|
return libc.Int32FromUint32(v1)
|
|
}
|
|
|
|
func Xsqlite3_strnicmp(tls *libc.TLS, zLeft uintptr, zRight uintptr, N int32) (r int32) {
|
|
var a, b uintptr
|
|
var v1 int32
|
|
_, _, _ = a, b, v1
|
|
if zLeft == uintptr(0) {
|
|
if zRight != 0 {
|
|
v1 = -int32(1)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
return v1
|
|
} else {
|
|
if zRight == uintptr(0) {
|
|
return int32(1)
|
|
}
|
|
}
|
|
a = zLeft
|
|
b = zRight
|
|
for {
|
|
v1 = N
|
|
N = N - 1
|
|
if !(v1 > 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up(a))) != 0 && libc.Int32FromUint8(_sqlite3UpperToLower[**(**uint8)(__ccgo_up(a))]) == libc.Int32FromUint8(_sqlite3UpperToLower[**(**uint8)(__ccgo_up(b))])) {
|
|
break
|
|
}
|
|
a = a + 1
|
|
b = b + 1
|
|
}
|
|
if N < 0 {
|
|
v1 = 0
|
|
} else {
|
|
v1 = libc.Int32FromUint8(_sqlite3UpperToLower[**(**uint8)(__ccgo_up(a))]) - libc.Int32FromUint8(_sqlite3UpperToLower[**(**uint8)(__ccgo_up(b))])
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return a boolean value for a query parameter.
|
|
// */
|
|
func Xsqlite3_uri_boolean(tls *libc.TLS, zFilename uintptr, zParam uintptr, bDflt int32) (r int32) {
|
|
var z uintptr
|
|
var v1 int32
|
|
_, _ = z, v1
|
|
z = Xsqlite3_uri_parameter(tls, zFilename, zParam)
|
|
bDflt = libc.BoolInt32(bDflt != 0)
|
|
if z != 0 {
|
|
v1 = libc.Int32FromUint8(_sqlite3GetBoolean(tls, z, libc.Uint8FromInt32(bDflt)))
|
|
} else {
|
|
v1 = bDflt
|
|
}
|
|
return v1
|
|
}
|
|
|
|
func Xsqlite3_value_encoding(tls *libc.TLS, pVal uintptr) (r int32) {
|
|
return libc.Int32FromUint8((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fenc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Return true if a parameter value originated from an sqlite3_bind() */
|
|
func Xsqlite3_value_frombind(tls *libc.TLS, pVal uintptr) (r int32) {
|
|
return libc.BoolInt32(libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&int32(MEM_FromBind) != 0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Return true if a parameter to xUpdate represents an unchanged column */
|
|
func Xsqlite3_value_nochange(tls *libc.TLS, pVal uintptr) (r int32) {
|
|
return libc.BoolInt32(libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&(libc.Int32FromInt32(MEM_Null)|libc.Int32FromInt32(MEM_Zero)) == libc.Int32FromInt32(MEM_Null)|libc.Int32FromInt32(MEM_Zero))
|
|
}
|
|
|
|
func Xsqlite3_value_subtype(tls *libc.TLS, pVal uintptr) (r uint32) {
|
|
var pMem uintptr
|
|
var v1 int32
|
|
_, _ = pMem, v1
|
|
pMem = pVal
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Subtype) != 0 {
|
|
v1 = libc.Int32FromUint8((*TMem)(unsafe.Pointer(pMem)).FeSubtype)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
return libc.Uint32FromInt32(v1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five
|
|
// ** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating
|
|
// ** point number string BLOB NULL
|
|
// */
|
|
func Xsqlite3_value_type(tls *libc.TLS, pVal uintptr) (r int32) {
|
|
return libc.Int32FromUint8(_aType[libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&int32(MEM_AffMask)])
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Call from within the xCreate() or xConnect() methods to provide
|
|
// ** the SQLite core with additional information about the behavior
|
|
// ** of the virtual table being implemented.
|
|
// */
|
|
func Xsqlite3_vtab_config(tls *libc.TLS, db uintptr, op int32, va uintptr) (r int32) {
|
|
var ap Tva_list
|
|
var p uintptr
|
|
var rc int32
|
|
_, _, _ = ap, p, rc
|
|
rc = SQLITE_OK
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
p = (*Tsqlite3)(unsafe.Pointer(db)).FpVtabCtx
|
|
if !(p != 0) {
|
|
rc = _sqlite3MisuseError(tls, int32(163230))
|
|
} else {
|
|
ap = va
|
|
switch op {
|
|
case int32(SQLITE_VTAB_CONSTRAINT_SUPPORT):
|
|
(*TVTable)(unsafe.Pointer((*TVtabCtx)(unsafe.Pointer(p)).FpVTable)).FbConstraint = libc.Uint8FromInt32(libc.VaInt32(&ap))
|
|
case int32(SQLITE_VTAB_INNOCUOUS):
|
|
(*TVTable)(unsafe.Pointer((*TVtabCtx)(unsafe.Pointer(p)).FpVTable)).FeVtabRisk = uint8(SQLITE_VTABRISK_Low)
|
|
case int32(SQLITE_VTAB_DIRECTONLY):
|
|
(*TVTable)(unsafe.Pointer((*TVtabCtx)(unsafe.Pointer(p)).FpVTable)).FeVtabRisk = uint8(SQLITE_VTABRISK_High)
|
|
case int32(SQLITE_VTAB_USES_ALL_SCHEMAS):
|
|
(*TVTable)(unsafe.Pointer((*TVtabCtx)(unsafe.Pointer(p)).FpVTable)).FbAllSchemas = uint8(1)
|
|
default:
|
|
rc = _sqlite3MisuseError(tls, int32(163252))
|
|
break
|
|
}
|
|
_ = ap
|
|
}
|
|
if rc != SQLITE_OK {
|
|
_sqlite3Error(tls, db, rc)
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
/************** End of vtab.c ************************************************/
|
|
/************** Begin file wherecode.c ***************************************/
|
|
/*
|
|
** 2015-06-06
|
|
**
|
|
** 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 module contains C code that generates VDBE code used to process
|
|
** the WHERE clause of SQL statements.
|
|
**
|
|
** This file was split off from where.c on 2015-06-06 in order to reduce the
|
|
** size of where.c and make it easier to edit. This file contains the routines
|
|
** that actually generate the bulk of the WHERE loop code. The original where.c
|
|
** file retains the code that does query planning and analysis.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
/************** Include whereInt.h in the middle of wherecode.c **************/
|
|
/************** Begin file whereInt.h ****************************************/
|
|
/*
|
|
** 2013-11-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 structure and macro definitions for the query
|
|
** planner logic in "where.c". These definitions are broken out into
|
|
** a separate source file for easier editing.
|
|
*/
|
|
|
|
const _IOLBF = 1
|
|
|
|
const _IONBF = 2
|
|
|
|
const __SIZEOF_WCHAR_T__ = 4
|
|
|
|
const __SIZEOF_WINT_T__ = 4
|
|
|
|
const __WCHAR_WIDTH__ = 32
|
|
|
|
const __WINT_WIDTH__ = 32
|
|
|
|
const __restrict_arr = 0
|
|
|
|
/* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in
|
|
** length.
|
|
** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and
|
|
** (N-13)/2 bytes in length. */
|
|
var _aFlag = [2]Tu16{
|
|
0: libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Blob) | libc.Int32FromInt32(MEM_Ephem)),
|
|
1: libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Str) | libc.Int32FromInt32(MEM_Ephem)),
|
|
}
|
|
|
|
/* If the column value is a string, we need a persistent value, not
|
|
** a MEM_Ephem value. This branch is a fast short-cut that is equivalent
|
|
** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize().
|
|
*/
|
|
var _aFlag1 = [2]Tu16{
|
|
0: uint16(MEM_Blob),
|
|
1: libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Str) | libc.Int32FromInt32(MEM_Term)),
|
|
}
|
|
|
|
var _aKeyword = [7]struct {
|
|
Fi Tu8
|
|
FnChar Tu8
|
|
Fcode Tu8
|
|
}{
|
|
0: {
|
|
FnChar: uint8(7),
|
|
Fcode: uint8(JT_NATURAL),
|
|
},
|
|
1: {
|
|
Fi: uint8(6),
|
|
FnChar: uint8(4),
|
|
Fcode: libc.Uint8FromInt32(libc.Int32FromInt32(JT_LEFT) | libc.Int32FromInt32(JT_OUTER)),
|
|
},
|
|
2: {
|
|
Fi: uint8(10),
|
|
FnChar: uint8(5),
|
|
Fcode: uint8(JT_OUTER),
|
|
},
|
|
3: {
|
|
Fi: uint8(14),
|
|
FnChar: uint8(5),
|
|
Fcode: libc.Uint8FromInt32(libc.Int32FromInt32(JT_RIGHT) | libc.Int32FromInt32(JT_OUTER)),
|
|
},
|
|
4: {
|
|
Fi: uint8(19),
|
|
FnChar: uint8(4),
|
|
Fcode: libc.Uint8FromInt32(libc.Int32FromInt32(JT_LEFT) | libc.Int32FromInt32(JT_RIGHT) | libc.Int32FromInt32(JT_OUTER)),
|
|
},
|
|
5: {
|
|
Fi: uint8(23),
|
|
FnChar: uint8(5),
|
|
Fcode: uint8(JT_INNER),
|
|
},
|
|
6: {
|
|
Fi: uint8(28),
|
|
FnChar: uint8(5),
|
|
Fcode: libc.Uint8FromInt32(libc.Int32FromInt32(JT_INNER) | libc.Int32FromInt32(JT_CROSS)),
|
|
},
|
|
}
|
|
|
|
var _aWindowFuncs = [15]TFuncDef{
|
|
0: {
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_row_numberName)),
|
|
},
|
|
1: {
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_dense_rankName)),
|
|
},
|
|
2: {
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_rankName)),
|
|
},
|
|
3: {
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_percent_rankName)),
|
|
},
|
|
4: {
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_cume_distName)),
|
|
},
|
|
5: {
|
|
FnArg: int16(1),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_ntileName)),
|
|
},
|
|
6: {
|
|
FnArg: int16(1),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_last_valueName)),
|
|
},
|
|
7: {
|
|
FnArg: int16(2),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_nth_valueName)),
|
|
},
|
|
8: {
|
|
FnArg: int16(1),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_first_valueName)),
|
|
},
|
|
9: {
|
|
FnArg: int16(1),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_leadName)),
|
|
},
|
|
10: {
|
|
FnArg: int16(2),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_leadName)),
|
|
},
|
|
11: {
|
|
FnArg: int16(3),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_leadName)),
|
|
},
|
|
12: {
|
|
FnArg: int16(1),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_lagName)),
|
|
},
|
|
13: {
|
|
FnArg: int16(2),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_lagName)),
|
|
},
|
|
14: {
|
|
FnArg: int16(3),
|
|
FfuncFlags: libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_BUILTIN) | libc.Int32FromInt32(SQLITE_UTF8) | libc.Int32FromInt32(SQLITE_FUNC_WINDOW) | libc.Int32FromInt32(0)),
|
|
FzName: uintptr(unsafe.Pointer(&_lagName)),
|
|
},
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This variant of sqlite3BtreePayload() works even if the cursor has not
|
|
// ** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read()
|
|
// ** interface.
|
|
// */
|
|
func _accessPayloadChecked(tls *libc.TLS, pCur uintptr, offset Tu32, amt Tu32, pBuf uintptr) (r int32) {
|
|
var rc, v1 int32
|
|
_, _ = rc, v1
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == int32(CURSOR_INVALID) {
|
|
return int32(SQLITE_ABORT)
|
|
}
|
|
rc = _btreeRestoreCursorPosition(tls, pCur)
|
|
if rc != 0 {
|
|
v1 = rc
|
|
} else {
|
|
v1 = _accessPayload(tls, pCur, offset, amt, pBuf, 0)
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine takes the module argument that has been accumulating
|
|
// ** in pParse->zArg[] and appends it to the list of arguments on the
|
|
// ** virtual table currently under construction in pParse->pTable.
|
|
// */
|
|
func _addArgumentToVtab(tls *libc.TLS, pParse uintptr) {
|
|
var db, z uintptr
|
|
var n int32
|
|
_, _, _ = db, n, z
|
|
if (*TParse)(unsafe.Pointer(pParse)).FsArg.Fz != 0 && (*TParse)(unsafe.Pointer(pParse)).FpNewTable != 0 {
|
|
z = (*TParse)(unsafe.Pointer(pParse)).FsArg.Fz
|
|
n = libc.Int32FromUint32((*TParse)(unsafe.Pointer(pParse)).FsArg.Fn)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
_addModuleArgument(tls, pParse, (*TParse)(unsafe.Pointer(pParse)).FpNewTable, _sqlite3DbStrNDup(tls, db, z, libc.Uint64FromInt32(n)))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
|
|
// ** on the same B-tree as pCur.
|
|
// **
|
|
// ** This can occur if a database is corrupt with two or more SQL tables
|
|
// ** pointing to the same b-tree. If an insert occurs on one SQL table
|
|
// ** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
|
|
// ** table linked to the same b-tree. If the secondary insert causes a
|
|
// ** rebalance, that can change content out from under the cursor on the
|
|
// ** first SQL table, violating invariants on the first insert.
|
|
// */
|
|
func _anotherValidCursor(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
var pOther uintptr
|
|
_ = pOther
|
|
pOther = (*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FpCursor
|
|
for {
|
|
if !(pOther != 0) {
|
|
break
|
|
}
|
|
if pOther != pCur && libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pOther)).FeState) == CURSOR_VALID && (*TBtCursor)(unsafe.Pointer(pOther)).FpPage == (*TBtCursor)(unsafe.Pointer(pCur)).FpPage {
|
|
return _sqlite3CorruptError(tls, int32(82340))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pOther = (*TBtCursor)(unsafe.Pointer(pOther)).FpNext
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Perform a read or write operation on a blob
|
|
// */
|
|
func _blobReadWrite(tls *libc.TLS, pBlob uintptr, z uintptr, n int32, iOffset int32, __ccgo_fp_xCall uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, p, v uintptr
|
|
var iKey Tsqlite3_int64
|
|
var rc int32
|
|
var _ /* bDiff at bp+0 */ int32
|
|
_, _, _, _, _ = db, iKey, p, rc, v
|
|
rc = SQLITE_OK
|
|
p = pBlob
|
|
if p == uintptr(0) {
|
|
return _sqlite3MisuseError(tls, int32(106385))
|
|
}
|
|
db = (*TIncrblob)(unsafe.Pointer(p)).Fdb
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
v = (*TIncrblob)(unsafe.Pointer(p)).FpStmt
|
|
if n < 0 || iOffset < 0 || int64(iOffset)+int64(n) > int64((*TIncrblob)(unsafe.Pointer(p)).FnByte) {
|
|
/* Request is out of range. Return a transient error. */
|
|
rc = int32(SQLITE_ERROR)
|
|
} else {
|
|
if v == uintptr(0) {
|
|
/* If there is no statement handle, then the blob-handle has
|
|
** already been invalidated. Return SQLITE_ABORT in this case.
|
|
*/
|
|
rc = int32(SQLITE_ABORT)
|
|
} else {
|
|
/* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
|
|
** returned, clean-up the statement handle.
|
|
*/
|
|
_sqlite3BtreeEnterCursor(tls, (*TIncrblob)(unsafe.Pointer(p)).FpCsr)
|
|
if __ccgo_fp_xCall == __ccgo_fp(_sqlite3BtreePutData) && (*Tsqlite3)(unsafe.Pointer(db)).FxPreUpdateCallback != 0 {
|
|
/* If a pre-update hook is registered and this is a write cursor,
|
|
** invoke it here.
|
|
**
|
|
** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this
|
|
** operation should really be an SQLITE_UPDATE. This is probably
|
|
** incorrect, but is convenient because at this point the new.* values
|
|
** are not easily obtainable. And for the sessions module, an
|
|
** SQLITE_UPDATE where the PK columns do not change is handled in the
|
|
** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually
|
|
** slightly more efficient). Since you cannot write to a PK column
|
|
** using the incremental-blob API, this works. For the sessions module
|
|
** anyhow.
|
|
*/
|
|
if _sqlite3BtreeCursorIsValidNN(tls, (*TIncrblob)(unsafe.Pointer(p)).FpCsr) == 0 {
|
|
/* If the cursor is not currently valid, try to reseek it. This
|
|
** always either fails or finds the correct row - the cursor will
|
|
** have been marked permanently CURSOR_INVALID if the open row has
|
|
** been deleted. */
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
rc = _sqlite3BtreeCursorRestore(tls, (*TIncrblob)(unsafe.Pointer(p)).FpCsr, bp)
|
|
}
|
|
if _sqlite3BtreeCursorIsValidNN(tls, (*TIncrblob)(unsafe.Pointer(p)).FpCsr) != 0 {
|
|
iKey = _sqlite3BtreeIntegerKey(tls, (*TIncrblob)(unsafe.Pointer(p)).FpCsr)
|
|
_sqlite3VdbePreUpdateHook(tls, v, **(**uintptr)(__ccgo_up((*TVdbe)(unsafe.Pointer(v)).FapCsr)), int32(SQLITE_DELETE), (*TIncrblob)(unsafe.Pointer(p)).FzDb, (*TIncrblob)(unsafe.Pointer(p)).FpTab, iKey, -int32(1), libc.Int32FromUint16((*TIncrblob)(unsafe.Pointer(p)).FiCol))
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = (*(*func(*libc.TLS, uintptr, Tu32, Tu32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xCall})))(tls, (*TIncrblob)(unsafe.Pointer(p)).FpCsr, libc.Uint32FromInt32(iOffset+(*TIncrblob)(unsafe.Pointer(p)).FiOffset), libc.Uint32FromInt32(n), z)
|
|
}
|
|
_sqlite3BtreeLeaveCursor(tls, (*TIncrblob)(unsafe.Pointer(p)).FpCsr)
|
|
if rc == int32(SQLITE_ABORT) {
|
|
_sqlite3VdbeFinalize(tls, v)
|
|
(*TIncrblob)(unsafe.Pointer(p)).FpStmt = uintptr(0)
|
|
} else {
|
|
(*TVdbe)(unsafe.Pointer(v)).Frc = rc
|
|
}
|
|
}
|
|
}
|
|
_sqlite3Error(tls, db, rc)
|
|
rc = _sqlite3ApiExit(tls, db, rc)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* This is a helper function to impliesNotNullRow(). In this routine,
|
|
// ** set pWalker->eCode to one only if *both* of the input expressions
|
|
// ** separately have the implies-not-null-row property.
|
|
// */
|
|
func _bothImplyNotNullRow(tls *libc.TLS, pWalker uintptr, pE1 uintptr, pE2 uintptr) {
|
|
if libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) == 0 {
|
|
_sqlite3WalkExpr(tls, pWalker, pE1)
|
|
if (*TWalker)(unsafe.Pointer(pWalker)).FeCode != 0 {
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(0)
|
|
_sqlite3WalkExpr(tls, pWalker, pE2)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute the amount of freespace on the page. In other words, fill
|
|
// ** in the pPage->nFree field.
|
|
// */
|
|
func _btreeComputeFreeSpace(tls *libc.TLS, pPage uintptr) (r int32) {
|
|
var data uintptr
|
|
var hdr Tu8
|
|
var iCellFirst, iCellLast, nFree, pc, top, usableSize int32
|
|
var next, size Tu32
|
|
_, _, _, _, _, _, _, _, _, _ = data, hdr, iCellFirst, iCellLast, nFree, next, pc, size, top, usableSize /* Last possible cell or freeblock offset */
|
|
usableSize = libc.Int32FromUint32((*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPage)).FpBt)).FusableSize)
|
|
hdr = (*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset
|
|
data = (*TMemPage)(unsafe.Pointer(pPage)).FaData
|
|
/* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
|
|
** the start of the cell content area. A zero value for this integer is
|
|
** interpreted as 65536. */
|
|
top = (libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(libc.Int32FromUint8(hdr)+int32(5)))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(libc.Int32FromUint8(hdr)+int32(5)) + 1)))-int32(1))&int32(0xffff) + int32(1)
|
|
iCellFirst = libc.Int32FromUint8(hdr) + int32(8) + libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FchildPtrSize) + int32(2)*libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell)
|
|
iCellLast = usableSize - int32(4)
|
|
/* Compute the total free space on the page
|
|
** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
|
|
** start of the first freeblock on the page, or is zero if there are no
|
|
** freeblocks. */
|
|
pc = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(libc.Int32FromUint8(hdr)+int32(1)))))<<int32(8) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(libc.Int32FromUint8(hdr)+int32(1)) + 1)))
|
|
nFree = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(libc.Int32FromUint8(hdr)+int32(7))))) + top /* Init nFree to non-freeblock free space */
|
|
if pc > 0 {
|
|
if pc < top {
|
|
/* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
|
|
** always be at least one cell before the first freeblock.
|
|
*/
|
|
return _sqlite3CorruptError(tls, int32(75358))
|
|
}
|
|
for int32(1) != 0 {
|
|
if pc > iCellLast {
|
|
/* Freeblock off the end of the page */
|
|
return _sqlite3CorruptError(tls, int32(75363))
|
|
}
|
|
next = libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(pc))))<<libc.Int32FromInt32(8) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(pc) + 1))))
|
|
size = libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(pc+int32(2)))))<<libc.Int32FromInt32(8) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(pc+int32(2)) + 1))))
|
|
if size < uint32(4) {
|
|
/* Minimum freeblock size is 4 */
|
|
return _sqlite3CorruptError(tls, int32(75369))
|
|
}
|
|
nFree = libc.Int32FromUint32(libc.Uint32FromInt32(nFree) + size)
|
|
if next < libc.Uint32FromInt32(pc)+size+uint32(4) {
|
|
break
|
|
}
|
|
pc = libc.Int32FromUint32(next)
|
|
}
|
|
if next > uint32(0) {
|
|
/* Freeblock not in ascending order */
|
|
return _sqlite3CorruptError(tls, int32(75377))
|
|
}
|
|
if libc.Uint32FromInt32(pc)+size > libc.Uint32FromInt32(usableSize) {
|
|
/* Last freeblock extends past page end */
|
|
return _sqlite3CorruptError(tls, int32(75381))
|
|
}
|
|
}
|
|
/* At this point, nFree contains the sum of the offset to the start
|
|
** of the cell-content area plus the number of free bytes within
|
|
** the cell-content area. If this is greater than the usable-size
|
|
** of the page, then the page must be corrupted. This check also
|
|
** serves to verify that the offset to the start of the cell-content
|
|
** area, according to the page header, lies within the page.
|
|
*/
|
|
if nFree > usableSize || nFree < iCellFirst {
|
|
return _sqlite3CorruptError(tls, int32(75393))
|
|
}
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FnFree = libc.Int32FromUint16(libc.Uint16FromInt32(nFree - iCellFirst))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called from both BtreeCommitPhaseTwo() and BtreeRollback()
|
|
// ** at the conclusion of a transaction.
|
|
// */
|
|
func _btreeEndTransaction(tls *libc.TLS, p uintptr) {
|
|
var db, pBt uintptr
|
|
_, _ = db, pBt
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
db = (*TBtree)(unsafe.Pointer(p)).Fdb
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FbDoTruncate = uint8(0)
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) > TRANS_NONE && (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeRead > int32(1) {
|
|
/* If there are other active statements that belong to this database
|
|
** handle, downgrade to a read-only transaction. The other statements
|
|
** may still be reading from the database. */
|
|
_downgradeAllSharedCacheTableLocks(tls, p)
|
|
(*TBtree)(unsafe.Pointer(p)).FinTrans = uint8(TRANS_READ)
|
|
} else {
|
|
/* If the handle had any kind of transaction open, decrement the
|
|
** transaction count of the shared btree. If the transaction count
|
|
** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused()
|
|
** call below will unlock the pager. */
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) != TRANS_NONE {
|
|
_clearAllSharedCacheTableLocks(tls, p)
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FnTransaction = (*TBtShared)(unsafe.Pointer(pBt)).FnTransaction - 1
|
|
if 0 == (*TBtShared)(unsafe.Pointer(pBt)).FnTransaction {
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FinTransaction = uint8(TRANS_NONE)
|
|
}
|
|
}
|
|
/* Set the current transaction state to TRANS_NONE and unlock the
|
|
** pager if this call closed the only read or write transaction. */
|
|
(*TBtree)(unsafe.Pointer(p)).FinTrans = uint8(TRANS_NONE)
|
|
_unlockBtreeIfUnused(tls, pBt)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize the auxiliary information for a disk block.
|
|
// **
|
|
// ** Return SQLITE_OK on success. If we see that the page does
|
|
// ** not contain a well-formed database page, then return
|
|
// ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
|
|
// ** guarantee that the page is well-formed. It only shows that
|
|
// ** we failed to detect any corruption.
|
|
// */
|
|
func _btreeInitPage(tls *libc.TLS, pPage uintptr) (r int32) {
|
|
var data, pBt uintptr
|
|
_, _ = data, pBt /* The main btree structure */
|
|
pBt = (*TMemPage)(unsafe.Pointer(pPage)).FpBt
|
|
data = (*TMemPage)(unsafe.Pointer(pPage)).FaData + uintptr((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset)
|
|
/* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
|
|
** the b-tree page type. */
|
|
if _decodeFlags(tls, pPage, libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data)))) != 0 {
|
|
return _sqlite3CorruptError(tls, int32(75461))
|
|
}
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FmaskPage = uint16((*TBtShared)(unsafe.Pointer(pBt)).FpageSize - libc.Uint32FromInt32(1))
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FnOverflow = uint8(0)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FcellOffset = libc.Uint16FromInt32(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset) + libc.Int32FromInt32(8) + libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FchildPtrSize))
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx = data + uintptr((*TMemPage)(unsafe.Pointer(pPage)).FchildPtrSize) + uintptr(8)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FaDataEnd = (*TMemPage)(unsafe.Pointer(pPage)).FaData + uintptr((*TBtShared)(unsafe.Pointer(pBt)).FpageSize)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FaDataOfst = (*TMemPage)(unsafe.Pointer(pPage)).FaData + uintptr((*TMemPage)(unsafe.Pointer(pPage)).FchildPtrSize)
|
|
/* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
|
|
** number of cells on the page. */
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FnCell = libc.Uint16FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + 3)))<<libc.Int32FromInt32(8) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + 3 + 1))))
|
|
if uint32((*TMemPage)(unsafe.Pointer(pPage)).FnCell) > ((*TBtShared)(unsafe.Pointer(pBt)).FpageSize-uint32(8))/uint32(6) {
|
|
/* To many cells for a single page. The page must be corrupt */
|
|
return _sqlite3CorruptError(tls, int32(75475))
|
|
}
|
|
/* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
|
|
** possible for a root page of a table that contains no rows) then the
|
|
** offset to the cell content area will equal the page size minus the
|
|
** bytes of reserved space. */
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FnFree = -int32(1) /* Indicate that this value is yet uncomputed */
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FisInit = uint8(1)
|
|
if (*Tsqlite3)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).Fdb)).Fflags&uint64(SQLITE_CellSizeCk) != 0 {
|
|
return _btreeCellSizeCheck(tls, pPage)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** In this version of BtreeMoveto, pKey is a packed index record
|
|
// ** such as is generated by the OP_MakeRecord opcode. Unpack the
|
|
// ** record and then call sqlite3BtreeIndexMoveto() to do the work.
|
|
// */
|
|
func _btreeMoveto(tls *libc.TLS, pCur uintptr, pKey uintptr, nKey Ti64, bias int32, pRes uintptr) (r int32) {
|
|
var pIdxKey, pKeyInfo uintptr
|
|
var rc int32
|
|
_, _, _ = pIdxKey, pKeyInfo, rc /* Unpacked index key */
|
|
if pKey != 0 {
|
|
pKeyInfo = (*TBtCursor)(unsafe.Pointer(pCur)).FpKeyInfo
|
|
pIdxKey = _sqlite3VdbeAllocUnpackedRecord(tls, pKeyInfo)
|
|
if pIdxKey == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
_sqlite3VdbeRecordUnpack(tls, int32(nKey), pKey, pIdxKey)
|
|
if libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(pIdxKey)).FnField) == 0 || libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(pIdxKey)).FnField) > libc.Int32FromUint16((*TKeyInfo)(unsafe.Pointer(pKeyInfo)).FnAllField) {
|
|
rc = _sqlite3CorruptError(tls, int32(74103))
|
|
} else {
|
|
rc = _sqlite3BtreeIndexMoveto(tls, pCur, pIdxKey, pRes)
|
|
}
|
|
_sqlite3DbFree(tls, (*TKeyInfo)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpKeyInfo)).Fdb, pIdxKey)
|
|
} else {
|
|
pIdxKey = uintptr(0)
|
|
rc = _sqlite3BtreeTableMoveto(tls, pCur, nKey, bias, pRes)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Overwrite the cell that cursor pCur is pointing to with fresh content
|
|
// ** contained in pX.
|
|
// */
|
|
func _btreeOverwriteCell(tls *libc.TLS, pCur uintptr, pX uintptr) (r int32) {
|
|
var nTotal int32
|
|
var pPage uintptr
|
|
_, _ = nTotal, pPage
|
|
nTotal = (*TBtreePayload)(unsafe.Pointer(pX)).FnData + (*TBtreePayload)(unsafe.Pointer(pX)).FnZero /* Total bytes of to write */
|
|
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage /* Page being written */
|
|
if (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload+uintptr((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnLocal) > (*TMemPage)(unsafe.Pointer(pPage)).FaDataEnd || (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload < (*TMemPage)(unsafe.Pointer(pPage)).FaData+uintptr((*TMemPage)(unsafe.Pointer(pPage)).FcellOffset) {
|
|
return _sqlite3CorruptError(tls, int32(82592))
|
|
}
|
|
if libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnLocal) == nTotal {
|
|
/* The entire cell is local */
|
|
return _btreeOverwriteContent(tls, pPage, (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload, pX, 0, libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnLocal))
|
|
} else {
|
|
/* The cell contains overflow content */
|
|
return _btreeOverwriteOverflowCell(tls, pCur, pX)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Overwrite the cell that cursor pCur is pointing to with fresh content
|
|
// ** contained in pX. In this variant, pCur is pointing to an overflow
|
|
// ** cell.
|
|
// */
|
|
func _btreeOverwriteOverflowCell(tls *libc.TLS, pCur uintptr, pX uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iOffset, nTotal, rc int32
|
|
var ovflPageSize Tu32
|
|
var ovflPgno TPgno
|
|
var pBt uintptr
|
|
var _ /* pPage at bp+0 */ uintptr
|
|
_, _, _, _, _, _ = iOffset, nTotal, ovflPageSize, ovflPgno, pBt, rc /* Next byte of pX->pData to write */
|
|
nTotal = (*TBtreePayload)(unsafe.Pointer(pX)).FnData + (*TBtreePayload)(unsafe.Pointer(pX)).FnZero /* Return code */
|
|
**(**uintptr)(__ccgo_up(bp)) = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage /* Size to write on overflow page */
|
|
/* pCur is an overflow cell */
|
|
/* Overwrite the local portion first */
|
|
rc = _btreeOverwriteContent(tls, **(**uintptr)(__ccgo_up(bp)), (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload, pX, 0, libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnLocal))
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
/* Now overwrite the overflow pages */
|
|
iOffset = libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnLocal)
|
|
ovflPgno = _sqlite3Get4byte(tls, (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload+uintptr(iOffset))
|
|
pBt = (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpBt
|
|
ovflPageSize = (*TBtShared)(unsafe.Pointer(pBt)).FusableSize - uint32(4)
|
|
for cond := true; cond; cond = iOffset < nTotal {
|
|
rc = _btreeGetPage(tls, pBt, ovflPgno, bp, 0)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
if _sqlite3PagerPageRefcount(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpDbPage) != int32(1) || (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FisInit != 0 {
|
|
rc = _sqlite3CorruptError(tls, int32(82564))
|
|
} else {
|
|
if libc.Uint32FromInt32(iOffset)+ovflPageSize < libc.Uint32FromInt32(nTotal) {
|
|
ovflPgno = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaData)
|
|
} else {
|
|
ovflPageSize = libc.Uint32FromInt32(nTotal - iOffset)
|
|
}
|
|
rc = _btreeOverwriteContent(tls, **(**uintptr)(__ccgo_up(bp)), (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaData+uintptr(4), pX, iOffset, libc.Int32FromUint32(ovflPageSize))
|
|
}
|
|
_sqlite3PagerUnref(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpDbPage)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
iOffset = libc.Int32FromUint32(uint32(iOffset) + ovflPageSize)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert a DbPage obtained from the pager into a MemPage used by
|
|
// ** the btree layer.
|
|
// */
|
|
func _btreePageFromDbPage(tls *libc.TLS, pDbPage uintptr, pgno TPgno, pBt uintptr) (r uintptr) {
|
|
var pPage uintptr
|
|
var v1 int32
|
|
_, _ = pPage, v1
|
|
pPage = _sqlite3PagerGetExtra(tls, pDbPage)
|
|
if pgno != (*TMemPage)(unsafe.Pointer(pPage)).Fpgno {
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FaData = _sqlite3PagerGetData(tls, pDbPage)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FpDbPage = pDbPage
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FpBt = pBt
|
|
(*TMemPage)(unsafe.Pointer(pPage)).Fpgno = pgno
|
|
if pgno == uint32(1) {
|
|
v1 = int32(100)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset = libc.Uint8FromInt32(v1)
|
|
}
|
|
return pPage
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The following routines are implementations of the MemPage.xParseCell()
|
|
// ** method.
|
|
// **
|
|
// ** Parse a cell content block and fill in the CellInfo structure.
|
|
// **
|
|
// ** btreeParseCellPtr() => table btree leaf nodes
|
|
// ** btreeParseCellNoPayload() => table btree internal nodes
|
|
// ** btreeParseCellPtrIndex() => index btree nodes
|
|
// **
|
|
// ** There is also a wrapper function btreeParseCell() that works for
|
|
// ** all MemPage types and that references the cell by index rather than
|
|
// ** by pointer.
|
|
// */
|
|
func _btreeParseCellPtrNoPayload(tls *libc.TLS, pPage uintptr, pCell uintptr, pInfo uintptr) {
|
|
_ = pPage
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnSize = libc.Uint16FromInt32(int32(4) + libc.Int32FromUint8(_sqlite3GetVarint(tls, pCell+4, pInfo)))
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnPayload = uint32(0)
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnLocal = uint16(0)
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FpPayload = uintptr(0)
|
|
return
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Given a record with nPayload bytes of payload stored within btree
|
|
// ** page pPage, return the number of bytes of payload stored locally.
|
|
// */
|
|
func _btreePayloadToLocal(tls *libc.TLS, pPage uintptr, nPayload Ti64) (r int32) {
|
|
var maxLocal, minLocal, surplus, v1 int32
|
|
_, _, _, _ = maxLocal, minLocal, surplus, v1 /* Maximum amount of payload held locally */
|
|
maxLocal = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal)
|
|
if nPayload <= int64(maxLocal) {
|
|
return int32(nPayload)
|
|
} else { /* Overflow payload available for local storage */
|
|
minLocal = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FminLocal)
|
|
surplus = int32(int64(minLocal) + (nPayload-int64(minLocal))%libc.Int64FromUint32((*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPage)).FpBt)).FusableSize-libc.Uint32FromInt32(4)))
|
|
if surplus <= maxLocal {
|
|
v1 = surplus
|
|
} else {
|
|
v1 = minLocal
|
|
}
|
|
return v1
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Restore the cursor to the position it was in (or as close to as possible)
|
|
// ** when saveCursorPosition() was called. Note that this call deletes the
|
|
// ** saved position info stored by saveCursorPosition(), so there can be
|
|
// ** at most one effective restoreCursorPosition() call after each
|
|
// ** saveCursorPosition().
|
|
// */
|
|
func _btreeRestoreCursorPosition(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc int32
|
|
var _ /* skipNext at bp+0 */ int32
|
|
_ = rc
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == int32(CURSOR_FAULT) {
|
|
return (*TBtCursor)(unsafe.Pointer(pCur)).FskipNext
|
|
}
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_INVALID)
|
|
if _sqlite3FaultSim(tls, int32(410)) != 0 {
|
|
rc = int32(SQLITE_IOERR)
|
|
} else {
|
|
rc = _btreeMoveto(tls, pCur, (*TBtCursor)(unsafe.Pointer(pCur)).FpKey, (*TBtCursor)(unsafe.Pointer(pCur)).FnKey, 0, bp)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
Xsqlite3_free(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpKey)
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FpKey = uintptr(0)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FskipNext = **(**int32)(__ccgo_up(bp))
|
|
}
|
|
if (*TBtCursor)(unsafe.Pointer(pCur)).FskipNext != 0 && libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == CURSOR_VALID {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_SKIPNEXT)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the pBt->nPage field correctly, according to the current
|
|
// ** state of the database. Assume pBt->pPage1 is valid.
|
|
// */
|
|
func _btreeSetNPage(tls *libc.TLS, pBt uintptr, pPage1 uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var _ /* nPage at bp+0 */ int32
|
|
**(**int32)(__ccgo_up(bp)) = libc.Int32FromUint32(_sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pPage1)).FaData+28))
|
|
if **(**int32)(__ccgo_up(bp)) == 0 {
|
|
_sqlite3PagerPagecount(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, bp)
|
|
}
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FnPage = libc.Uint32FromInt32(**(**int32)(__ccgo_up(bp)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the octet_length() function
|
|
// */
|
|
func _bytelengthFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var m Ti64
|
|
var v1 int32
|
|
_, _ = m, v1
|
|
_ = argc
|
|
switch Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv))) {
|
|
case int32(SQLITE_BLOB):
|
|
Xsqlite3_result_int(tls, context, Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv))))
|
|
case int32(SQLITE_INTEGER):
|
|
fallthrough
|
|
case int32(SQLITE_FLOAT):
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(Xsqlite3_context_db_handle(tls, context))).Fenc) <= int32(SQLITE_UTF8) {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = int32(2)
|
|
}
|
|
m = int64(v1)
|
|
Xsqlite3_result_int64(tls, context, int64(Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv))))*m)
|
|
case int32(SQLITE_TEXT):
|
|
if Xsqlite3_value_encoding(tls, **(**uintptr)(__ccgo_up(argv))) <= int32(SQLITE_UTF8) {
|
|
Xsqlite3_result_int(tls, context, Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv))))
|
|
} else {
|
|
Xsqlite3_result_int(tls, context, Xsqlite3_value_bytes16(tls, **(**uintptr)(__ccgo_up(argv))))
|
|
}
|
|
default:
|
|
Xsqlite3_result_null(tls, context)
|
|
break
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the N-dimensional volume of the cell stored in *p.
|
|
// */
|
|
func _cellArea(tls *libc.TLS, pRtree uintptr, p uintptr) (r TRtreeDValue) {
|
|
var area TRtreeDValue
|
|
_ = area
|
|
area = libc.Float64FromInt32(1)
|
|
if libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FeCoordType) == RTREE_COORD_REAL32 {
|
|
switch libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim) {
|
|
case int32(5):
|
|
area = float64(*(*TRtreeValue)(unsafe.Pointer(p + 8 + 9*4)) - *(*TRtreeValue)(unsafe.Pointer(p + 8 + 8*4)))
|
|
fallthrough
|
|
case int32(4):
|
|
area = area * float64(*(*TRtreeValue)(unsafe.Pointer(p + 8 + 7*4))-*(*TRtreeValue)(unsafe.Pointer(p + 8 + 6*4)))
|
|
fallthrough
|
|
case int32(3):
|
|
area = area * float64(*(*TRtreeValue)(unsafe.Pointer(p + 8 + 5*4))-*(*TRtreeValue)(unsafe.Pointer(p + 8 + 4*4)))
|
|
fallthrough
|
|
case int32(2):
|
|
area = area * float64(*(*TRtreeValue)(unsafe.Pointer(p + 8 + 3*4))-*(*TRtreeValue)(unsafe.Pointer(p + 8 + 2*4)))
|
|
fallthrough
|
|
default:
|
|
area = area * float64(*(*TRtreeValue)(unsafe.Pointer(p + 8 + 1*4))-*(*TRtreeValue)(unsafe.Pointer(p + 8)))
|
|
}
|
|
} else {
|
|
switch libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim) {
|
|
case int32(5):
|
|
area = float64(int64(*(*int32)(unsafe.Pointer(p + 8 + 9*4))) - int64(*(*int32)(unsafe.Pointer(p + 8 + 8*4))))
|
|
fallthrough
|
|
case int32(4):
|
|
area = area * float64(int64(*(*int32)(unsafe.Pointer(p + 8 + 7*4)))-int64(*(*int32)(unsafe.Pointer(p + 8 + 6*4))))
|
|
fallthrough
|
|
case int32(3):
|
|
area = area * float64(int64(*(*int32)(unsafe.Pointer(p + 8 + 5*4)))-int64(*(*int32)(unsafe.Pointer(p + 8 + 4*4))))
|
|
fallthrough
|
|
case int32(2):
|
|
area = area * float64(int64(*(*int32)(unsafe.Pointer(p + 8 + 3*4)))-int64(*(*int32)(unsafe.Pointer(p + 8 + 2*4))))
|
|
fallthrough
|
|
default:
|
|
area = area * float64(int64(*(*int32)(unsafe.Pointer(p + 8 + 1*4)))-int64(*(*int32)(unsafe.Pointer(p + 8))))
|
|
}
|
|
}
|
|
return area
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the area covered by p2 is a subset of the area covered
|
|
// ** by p1. False otherwise.
|
|
// */
|
|
func _cellContains(tls *libc.TLS, pRtree uintptr, p1 uintptr, p2 uintptr) (r int32) {
|
|
var a1, a11, a2, a21 uintptr
|
|
var ii int32
|
|
_, _, _, _, _ = a1, a11, a2, a21, ii
|
|
if libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FeCoordType) == int32(RTREE_COORD_INT32) {
|
|
ii = 0
|
|
for {
|
|
if !(ii < libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2)) {
|
|
break
|
|
}
|
|
a1 = p1 + 8 + uintptr(ii)*4
|
|
a2 = p2 + 8 + uintptr(ii)*4
|
|
if *(*int32)(unsafe.Pointer(a2)) < *(*int32)(unsafe.Pointer(a1)) || *(*int32)(unsafe.Pointer(a2 + 1*4)) > *(*int32)(unsafe.Pointer(a1 + 1*4)) {
|
|
return 0
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + int32(2)
|
|
}
|
|
} else {
|
|
ii = 0
|
|
for {
|
|
if !(ii < libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2)) {
|
|
break
|
|
}
|
|
a11 = p1 + 8 + uintptr(ii)*4
|
|
a21 = p2 + 8 + uintptr(ii)*4
|
|
if *(*TRtreeValue)(unsafe.Pointer(a21)) < *(*TRtreeValue)(unsafe.Pointer(a11)) || *(*TRtreeValue)(unsafe.Pointer(a21 + 1*4)) > *(*TRtreeValue)(unsafe.Pointer(a11 + 1*4)) {
|
|
return 0
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + int32(2)
|
|
}
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the margin length of cell p. The margin length is the sum
|
|
// ** of the objects size in each dimension.
|
|
// */
|
|
func _cellMargin(tls *libc.TLS, pRtree uintptr, p uintptr) (r TRtreeDValue) {
|
|
var ii int32
|
|
var margin TRtreeDValue
|
|
var v1, v2 float64
|
|
_, _, _, _ = ii, margin, v1, v2
|
|
margin = libc.Float64FromInt32(0)
|
|
ii = libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2) - int32(2)
|
|
for cond := true; cond; cond = ii >= 0 {
|
|
if libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FeCoordType) == RTREE_COORD_REAL32 {
|
|
v1 = float64(*(*TRtreeValue)(unsafe.Pointer(p + 8 + uintptr(ii+int32(1))*4)))
|
|
} else {
|
|
v1 = float64(*(*int32)(unsafe.Pointer(p + 8 + uintptr(ii+int32(1))*4)))
|
|
}
|
|
if libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FeCoordType) == RTREE_COORD_REAL32 {
|
|
v2 = float64(*(*TRtreeValue)(unsafe.Pointer(p + 8 + uintptr(ii)*4)))
|
|
} else {
|
|
v2 = float64(*(*int32)(unsafe.Pointer(p + 8 + uintptr(ii)*4)))
|
|
}
|
|
margin = margin + (v1 - v2)
|
|
ii = ii - int32(2)
|
|
}
|
|
return margin
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Store the union of cells p1 and p2 in p1.
|
|
// */
|
|
func _cellUnion(tls *libc.TLS, pRtree uintptr, p1 uintptr, p2 uintptr) {
|
|
var ii, v3 int32
|
|
var v1 TRtreeValue
|
|
_, _, _ = ii, v1, v3
|
|
ii = 0
|
|
if libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FeCoordType) == RTREE_COORD_REAL32 {
|
|
for cond := true; cond; cond = ii < libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2) {
|
|
if *(*TRtreeValue)(unsafe.Pointer(p1 + 8 + uintptr(ii)*4)) < *(*TRtreeValue)(unsafe.Pointer(p2 + 8 + uintptr(ii)*4)) {
|
|
v1 = *(*TRtreeValue)(unsafe.Pointer(p1 + 8 + uintptr(ii)*4))
|
|
} else {
|
|
v1 = *(*TRtreeValue)(unsafe.Pointer(p2 + 8 + uintptr(ii)*4))
|
|
}
|
|
*(*TRtreeValue)(unsafe.Pointer(p1 + 8 + uintptr(ii)*4)) = v1
|
|
if *(*TRtreeValue)(unsafe.Pointer(p1 + 8 + uintptr(ii+int32(1))*4)) > *(*TRtreeValue)(unsafe.Pointer(p2 + 8 + uintptr(ii+int32(1))*4)) {
|
|
v1 = *(*TRtreeValue)(unsafe.Pointer(p1 + 8 + uintptr(ii+int32(1))*4))
|
|
} else {
|
|
v1 = *(*TRtreeValue)(unsafe.Pointer(p2 + 8 + uintptr(ii+int32(1))*4))
|
|
}
|
|
*(*TRtreeValue)(unsafe.Pointer(p1 + 8 + uintptr(ii+int32(1))*4)) = v1
|
|
ii = ii + int32(2)
|
|
}
|
|
} else {
|
|
for cond := true; cond; cond = ii < libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2) {
|
|
if *(*int32)(unsafe.Pointer(p1 + 8 + uintptr(ii)*4)) < *(*int32)(unsafe.Pointer(p2 + 8 + uintptr(ii)*4)) {
|
|
v3 = *(*int32)(unsafe.Pointer(p1 + 8 + uintptr(ii)*4))
|
|
} else {
|
|
v3 = *(*int32)(unsafe.Pointer(p2 + 8 + uintptr(ii)*4))
|
|
}
|
|
*(*int32)(unsafe.Pointer(p1 + 8 + uintptr(ii)*4)) = v3
|
|
if *(*int32)(unsafe.Pointer(p1 + 8 + uintptr(ii+int32(1))*4)) > *(*int32)(unsafe.Pointer(p2 + 8 + uintptr(ii+int32(1))*4)) {
|
|
v3 = *(*int32)(unsafe.Pointer(p1 + 8 + uintptr(ii+int32(1))*4))
|
|
} else {
|
|
v3 = *(*int32)(unsafe.Pointer(p2 + 8 + uintptr(ii+int32(1))*4))
|
|
}
|
|
*(*int32)(unsafe.Pointer(p1 + 8 + uintptr(ii+int32(1))*4)) = v3
|
|
ii = ii + int32(2)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the TEMP database is open, close it and mark the database schema
|
|
// ** as needing reloading. This must be done when using the SQLITE_TEMP_STORE
|
|
// ** or DEFAULT_TEMP_STORE pragmas.
|
|
// */
|
|
func _changeTempStorage(tls *libc.TLS, pParse uintptr, zStorageType uintptr) (r int32) {
|
|
var db uintptr
|
|
var ts int32
|
|
_, _ = db, ts
|
|
ts = _getTempStore(tls, zStorageType)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).Ftemp_store) == ts {
|
|
return SQLITE_OK
|
|
}
|
|
if _invalidateTempStorage(tls, pParse) != SQLITE_OK {
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Ftemp_store = libc.Uint8FromInt32(ts)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close all file descriptors accumulated in the unixInodeInfo->pUnused list.
|
|
// */
|
|
func _closePendingFds(tls *libc.TLS, pFile uintptr) {
|
|
var p, pInode, pNext uintptr
|
|
_, _, _ = p, pInode, pNext
|
|
pInode = (*TunixFile)(unsafe.Pointer(pFile)).FpInode
|
|
p = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpUnused
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
pNext = (*TUnixUnusedFd)(unsafe.Pointer(p)).FpNext
|
|
_robust_close(tls, pFile, (*TUnixUnusedFd)(unsafe.Pointer(p)).Ffd, int32(41675))
|
|
Xsqlite3_free(tls, p)
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = pNext
|
|
}
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FpUnused = uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for a comparison operator.
|
|
// */
|
|
func _codeCompare(tls *libc.TLS, pParse uintptr, pLeft uintptr, pRight uintptr, opcode int32, in1 int32, in2 int32, dest int32, jumpIfNull int32, isCommuted int32) (r int32) {
|
|
var addr, p5 int32
|
|
var p4 uintptr
|
|
_, _, _ = addr, p4, p5
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return 0
|
|
}
|
|
if isCommuted != 0 {
|
|
p4 = _sqlite3BinaryCompareCollSeq(tls, pParse, pRight, pLeft)
|
|
} else {
|
|
p4 = _sqlite3BinaryCompareCollSeq(tls, pParse, pLeft, pRight)
|
|
}
|
|
p5 = libc.Int32FromUint8(_binaryCompareP5(tls, pLeft, pRight, jumpIfNull))
|
|
addr = _sqlite3VdbeAddOp4(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, opcode, in2, dest, in1, p4, -int32(2))
|
|
_sqlite3VdbeChangeP5(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, libc.Uint16FromInt32(p5))
|
|
return addr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for a single equality term of the WHERE clause. An equality
|
|
// ** term can be either X=expr or X IN (...). pTerm is the term to be
|
|
// ** coded.
|
|
// **
|
|
// ** The current value for the constraint is left in a register, the index
|
|
// ** of which is returned. An attempt is made store the result in iTarget but
|
|
// ** this is only guaranteed for TK_ISNULL and TK_IN constraints. If the
|
|
// ** constraint is a TK_EQ or TK_IS, then the current value might be left in
|
|
// ** some other register and it is the caller's responsibility to compensate.
|
|
// **
|
|
// ** For a constraint of the form X=expr, the expression is evaluated in
|
|
// ** straight-line code. For constraints of the form X IN (...)
|
|
// ** this routine sets up a loop that will iterate over all values of X.
|
|
// */
|
|
func _codeEqualityTerm(tls *libc.TLS, pParse uintptr, pTerm uintptr, pLevel uintptr, iEq int32, bRev int32, iTarget int32) (r int32) {
|
|
var iReg int32
|
|
var pX uintptr
|
|
_, _ = iReg, pX
|
|
pX = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr /* Register holding results */
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pX)).Fop) == int32(TK_EQ) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pX)).Fop) == int32(TK_IS) {
|
|
iReg = _sqlite3ExprCodeTarget(tls, pParse, (*TExpr)(unsafe.Pointer(pX)).FpRight, iTarget)
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pX)).Fop) == int32(TK_ISNULL) {
|
|
iReg = iTarget
|
|
_sqlite3VdbeAddOp2(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, int32(OP_Null), 0, iReg)
|
|
} else {
|
|
iReg = iTarget
|
|
_codeINTerm(tls, pParse, pTerm, pLevel, iEq, bRev, iTarget)
|
|
}
|
|
}
|
|
/* As an optimization, try to disable the WHERE clause term that is
|
|
** driving the index as it will always be true. The correct answer is
|
|
** obtained regardless, but we might get the answer with fewer CPU cycles
|
|
** by omitting the term.
|
|
**
|
|
** But do not disable the term unless we are certain that the term is
|
|
** not a transitive constraint. For an example of where that does not
|
|
** work, see https://sqlite.org/forum/forumpost/eb8613976a (2021-05-04)
|
|
*/
|
|
if (*TWhereLoop)(unsafe.Pointer((*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop)).FwsFlags&uint32(WHERE_TRANSCONS) == uint32(0) || libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&int32(WO_EQUIV) == 0 {
|
|
_disableTerm(tls, pLevel, pTerm)
|
|
}
|
|
return iReg
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pMem currently only holds a string type (or maybe a BLOB that we can
|
|
// ** interpret as a string if we want to). Compute its corresponding
|
|
// ** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields
|
|
// ** accordingly.
|
|
// */
|
|
func _computeNumericType(tls *libc.TLS, pMem uintptr) (r Tu16) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc, v1 int32
|
|
var _ /* ix at bp+0 */ Tsqlite3_int64
|
|
_, _ = rc, v1
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Zero) != 0 {
|
|
v1 = _sqlite3VdbeMemExpandBlob(tls, pMem)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
if v1 != 0 {
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = 0
|
|
return uint16(MEM_Int)
|
|
}
|
|
rc = _sqlite3MemRealValueRC(tls, pMem, pMem)
|
|
if rc <= 0 {
|
|
if rc&int32(2) == 0 && _sqlite3Atoi64(tls, (*TMem)(unsafe.Pointer(pMem)).Fz, bp, (*TMem)(unsafe.Pointer(pMem)).Fn, (*TMem)(unsafe.Pointer(pMem)).Fenc) <= int32(1) {
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = **(**Tsqlite3_int64)(__ccgo_up(bp))
|
|
return uint16(MEM_Int)
|
|
} else {
|
|
return uint16(MEM_Real)
|
|
}
|
|
} else {
|
|
if rc&int32(2) == 0 && _sqlite3Atoi64(tls, (*TMem)(unsafe.Pointer(pMem)).Fz, bp, (*TMem)(unsafe.Pointer(pMem)).Fn, (*TMem)(unsafe.Pointer(pMem)).Fenc) == 0 {
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = **(**Tsqlite3_int64)(__ccgo_up(bp))
|
|
return uint16(MEM_Int)
|
|
}
|
|
}
|
|
return uint16(MEM_Real)
|
|
}
|
|
|
|
// 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
|
|
// */
|
|
func _dbpageBestIndex(tls *libc.TLS, tab uintptr, pIdxInfo uintptr) (r int32) {
|
|
var i, iPlan, v3 int32
|
|
var p, p1 uintptr
|
|
_, _, _, _, _ = i, iPlan, p, p1, v3
|
|
iPlan = 0
|
|
_ = tab
|
|
/* If there is a schema= constraint, it must be honored. Report a
|
|
** ridiculously large estimated cost if the schema= constraint is
|
|
** unavailable
|
|
*/
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FnConstraint) {
|
|
break
|
|
}
|
|
p = (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraint + uintptr(i)*12
|
|
if (*Tsqlite3_index_constraint)(unsafe.Pointer(p)).FiColumn != int32(DBPAGE_COLUMN_SCHEMA) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) != int32(SQLITE_INDEX_CONSTRAINT_EQ) {
|
|
goto _1
|
|
}
|
|
if !((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fusable != 0) {
|
|
/* No solution. */
|
|
return int32(SQLITE_CONSTRAINT)
|
|
}
|
|
iPlan = int32(2)
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(i)*8))).FargvIndex = int32(1)
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(i)*8))).Fomit = uint8(1)
|
|
break
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
/* If we reach this point, it means that either there is no schema=
|
|
** constraint (in which case we use the "main" schema) or else the
|
|
** schema constraint was accepted. Lower the estimated cost accordingly
|
|
*/
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedCost = float64(1e+06)
|
|
/* Check for constraints against pgno */
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FnConstraint) {
|
|
break
|
|
}
|
|
p1 = (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraint + uintptr(i)*12
|
|
if (*Tsqlite3_index_constraint)(unsafe.Pointer(p1)).Fusable != 0 && (*Tsqlite3_index_constraint)(unsafe.Pointer(p1)).FiColumn <= 0 && libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p1)).Fop) == int32(SQLITE_INDEX_CONSTRAINT_EQ) {
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedRows = int64(1)
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FidxFlags = int32(SQLITE_INDEX_SCAN_UNIQUE)
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedCost = float64(1)
|
|
if iPlan != 0 {
|
|
v3 = int32(2)
|
|
} else {
|
|
v3 = int32(1)
|
|
}
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(i)*8))).FargvIndex = v3
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(i)*8))).Fomit = uint8(1)
|
|
iPlan = iPlan | int32(1)
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FidxNum = iPlan
|
|
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)).ForderByConsumed = int32(1)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
func _dbpageRowid(tls *libc.TLS, pCursor uintptr, pRowid uintptr) (r int32) {
|
|
var pCsr uintptr
|
|
_ = pCsr
|
|
pCsr = pCursor
|
|
**(**Tsqlite_int64)(__ccgo_up(pRowid)) = libc.Int64FromUint32((*TDbpageCursor)(unsafe.Pointer(pCsr)).Fpgno)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete the cell at index iCell of node pNode. After removing the
|
|
// ** cell, adjust the r-tree data structure if required.
|
|
// */
|
|
func _deleteCell(tls *libc.TLS, pRtree uintptr, pNode uintptr, iCell int32, iHeight int32) (r int32) {
|
|
var pParent uintptr
|
|
var rc, v1 int32
|
|
_, _, _ = pParent, rc, v1
|
|
v1 = _fixLeafParent(tls, pRtree, pNode)
|
|
rc = v1
|
|
if SQLITE_OK != v1 {
|
|
return rc
|
|
}
|
|
/* Remove the cell from the node. This call just moves bytes around
|
|
** the in-memory node image, so it cannot fail.
|
|
*/
|
|
_nodeDeleteCell(tls, pRtree, pNode, iCell)
|
|
/* If the node is not the tree root and now has less than the minimum
|
|
** number of cells, remove it from the tree. Otherwise, update the
|
|
** cell in the parent node so that it tightly contains the updated
|
|
** node.
|
|
*/
|
|
pParent = (*TRtreeNode)(unsafe.Pointer(pNode)).FpParent
|
|
if pParent != 0 {
|
|
if _readInt16(tls, (*TRtreeNode)(unsafe.Pointer(pNode)).FzData+2) < ((*TRtree)(unsafe.Pointer(pRtree)).FiNodeSize-int32(4))/libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnBytesPerCell)/int32(3) {
|
|
rc = _removeNode(tls, pRtree, pNode, iHeight)
|
|
} else {
|
|
rc = _fixBoundingBox(tls, pRtree, pNode)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Write VDBE code to erase table pTab and all associated indices on disk.
|
|
// ** Code to update the sqlite_schema tables and internal schema definitions
|
|
// ** in case a root-page belonging to another table is moved by the btree layer
|
|
// ** is also added (this can happen with an auto-vacuum database).
|
|
// */
|
|
func _destroyTable(tls *libc.TLS, pParse uintptr, pTab uintptr) {
|
|
var iDb int32
|
|
var iDestroyed, iIdx, iLargest, iTab TPgno
|
|
var pIdx uintptr
|
|
_, _, _, _, _, _ = iDb, iDestroyed, iIdx, iLargest, iTab, pIdx
|
|
/* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
|
|
** is not defined), then it is important to call OP_Destroy on the
|
|
** table and index root-pages in order, starting with the numerically
|
|
** largest root-page number. This guarantees that none of the root-pages
|
|
** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
|
|
** following were coded:
|
|
**
|
|
** OP_Destroy 4 0
|
|
** ...
|
|
** OP_Destroy 5 0
|
|
**
|
|
** and root page 5 happened to be the largest root-page number in the
|
|
** database, then root page 5 would be moved to page 4 by the
|
|
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
|
|
** a free-list page.
|
|
*/
|
|
iTab = (*TTable)(unsafe.Pointer(pTab)).Ftnum
|
|
iDestroyed = uint32(0)
|
|
for int32(1) != 0 {
|
|
iLargest = uint32(0)
|
|
if iDestroyed == uint32(0) || iTab < iDestroyed {
|
|
iLargest = iTab
|
|
}
|
|
pIdx = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
iIdx = (*TIndex)(unsafe.Pointer(pIdx)).Ftnum
|
|
if (iDestroyed == uint32(0) || iIdx < iDestroyed) && iIdx > iLargest {
|
|
iLargest = iIdx
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
if iLargest == uint32(0) {
|
|
return
|
|
} else {
|
|
iDb = _sqlite3SchemaToIndex(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, (*TTable)(unsafe.Pointer(pTab)).FpSchema)
|
|
_destroyRootPage(tls, pParse, libc.Int32FromUint32(iLargest), iDb)
|
|
iDestroyed = iLargest
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine checks if there is a RESERVED lock held on the specified
|
|
// ** file by this or any other process. If the caller holds a SHARED
|
|
// ** or greater lock when it is called, then it is assumed that no other
|
|
// ** client may hold RESERVED. Or, if the caller holds no lock, then it
|
|
// ** is assumed another client holds RESERVED if the lock-file exists.
|
|
// */
|
|
func _dotlockCheckReservedLock(tls *libc.TLS, id uintptr, pResOut uintptr) (r int32) {
|
|
var pFile uintptr
|
|
_ = pFile
|
|
pFile = id
|
|
if libc.Int32FromUint8((*TunixFile)(unsafe.Pointer(pFile)).FeFileLock) >= int32(SHARED_LOCK) {
|
|
**(**int32)(__ccgo_up(pResOut)) = 0
|
|
} else {
|
|
**(**int32)(__ccgo_up(pResOut)) = libc.BoolInt32((*(*func(*libc.TLS, uintptr, int32) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(2)].FpCurrent})))(tls, (*TunixFile)(unsafe.Pointer(pFile)).FlockingContext, 0) == 0)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
var _dotlockIoFinder = uintptr(0)
|
|
|
|
func _dotlockIoFinderImpl(tls *libc.TLS, z uintptr, p uintptr) (r uintptr) {
|
|
_ = z
|
|
_ = p
|
|
return uintptr(unsafe.Pointer(&_dotlockIoMethods))
|
|
}
|
|
|
|
var _dotlockIoMethods = Tsqlite3_io_methods{
|
|
FiVersion: int32(1),
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Estimate the logarithm of the input value to base 2.
|
|
// */
|
|
func _estLog(tls *libc.TLS, N TLogEst) (r TLogEst) {
|
|
var v1 int32
|
|
_ = v1
|
|
if int32(N) <= int32(10) {
|
|
v1 = 0
|
|
} else {
|
|
v1 = int32(_sqlite3LogEst(tls, libc.Uint64FromInt16(N))) - int32(33)
|
|
}
|
|
return int16(v1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If expression pExpr is of type TK_SELECT, generate code to evaluate
|
|
// ** it. Return the register in which the result is stored (or, if the
|
|
// ** sub-select returns more than one column, the first in an array
|
|
// ** of registers in which the result is stored).
|
|
// **
|
|
// ** If pExpr is not a TK_SELECT expression, return 0.
|
|
// */
|
|
func _exprCodeSubselect(tls *libc.TLS, pParse uintptr, pExpr uintptr) (r int32) {
|
|
var reg int32
|
|
_ = reg
|
|
reg = 0
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_SELECT) {
|
|
reg = _sqlite3CodeSubselect(tls, pParse, pExpr)
|
|
}
|
|
return reg
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that evaluates an AND or OR operator leaving a
|
|
// ** boolean result in a register. pExpr is the AND/OR expression.
|
|
// ** Store the result in the "target" register. Use short-circuit
|
|
// ** evaluation to avoid computing both operands, if possible.
|
|
// **
|
|
// ** The code generated might require the use of a temporary register.
|
|
// ** If it does, then write the number of that temporary register
|
|
// ** into *pTmpReg. If not, leave *pTmpReg unchanged.
|
|
// */
|
|
func _exprCodeTargetAndOr(tls *libc.TLS, pParse uintptr, pExpr uintptr, target int32, pTmpReg uintptr) (r int32) {
|
|
var addrSkip, op, r1, r2, regSS, skipOp, v1 int32
|
|
var pAlt, v uintptr
|
|
_, _, _, _, _, _, _, _, _ = addrSkip, op, pAlt, r1, r2, regSS, skipOp, v, v1 /* Branch instruction that skips one of the operands */
|
|
regSS = 0 /* statement being coded */
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop)
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
pAlt = _sqlite3ExprSimplifiedAndOr(tls, pExpr)
|
|
if pAlt != pExpr {
|
|
r1 = _sqlite3ExprCodeTarget(tls, pParse, pAlt, target)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_And), r1, r1, target)
|
|
return target
|
|
}
|
|
if op == int32(TK_AND) {
|
|
v1 = int32(OP_IfNot)
|
|
} else {
|
|
v1 = int32(OP_If)
|
|
}
|
|
skipOp = v1
|
|
if _exprEvalRhsFirst(tls, pExpr) != 0 {
|
|
/* Compute the right operand first. Skip the computation of the left
|
|
** operand if the right operand fully determines the result */
|
|
v1 = _sqlite3ExprCodeTarget(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, target)
|
|
regSS = v1
|
|
r2 = v1
|
|
addrSkip = _sqlite3VdbeAddOp1(tls, v, skipOp, r2)
|
|
r1 = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, pTmpReg)
|
|
} else {
|
|
/* Compute the left operand first */
|
|
r1 = _sqlite3ExprCodeTarget(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, target)
|
|
if (*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pExpr)).FpRight)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subquery)) != uint32(0) {
|
|
/* Skip over the computation of the right operand if the right
|
|
** operand is a subquery and the left operand completely determines
|
|
** the result */
|
|
regSS = r1
|
|
addrSkip = _sqlite3VdbeAddOp1(tls, v, skipOp, r1)
|
|
} else {
|
|
v1 = libc.Int32FromInt32(0)
|
|
regSS = v1
|
|
addrSkip = v1
|
|
}
|
|
r2 = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, pTmpReg)
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, op, r2, r1, target)
|
|
if addrSkip != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Goto), 0, _sqlite3VdbeCurrentAddr(tls, v)+int32(2))
|
|
_sqlite3VdbeJumpHere(tls, v, addrSkip)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Or), regSS, regSS, target)
|
|
}
|
|
return target
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Commute a comparison operator. Expressions of the form "X op Y"
|
|
// ** are converted into "Y op X".
|
|
// */
|
|
func _exprCommute(tls *libc.TLS, pParse uintptr, pExpr uintptr) (r Tu16) {
|
|
var t uintptr
|
|
_ = t
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pExpr)).FpLeft)).Fop) == int32(TK_VECTOR) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pExpr)).FpRight)).Fop) == int32(TK_VECTOR) || _sqlite3BinaryCompareCollSeq(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, (*TExpr)(unsafe.Pointer(pExpr)).FpRight) != _sqlite3BinaryCompareCollSeq(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft) {
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) ^= uint32(EP_Commuted)
|
|
}
|
|
t = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FpRight = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FpLeft = t
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) >= int32(TK_GT) {
|
|
(*TExpr)(unsafe.Pointer(pExpr)).Fop = libc.Uint8FromInt32(libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) - int32(TK_GT) ^ int32(2) + int32(TK_GT))
|
|
}
|
|
return uint16(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Expression pVar is guaranteed to be an SQL variable. pExpr may be any
|
|
// ** type of expression.
|
|
// **
|
|
// ** If pExpr is a simple SQL value - an integer, real, string, blob
|
|
// ** or NULL value - then the VDBE currently being prepared is configured
|
|
// ** to re-prepare each time a new value is bound to variable pVar.
|
|
// **
|
|
// ** Additionally, if pExpr is a simple SQL value and the value is the
|
|
// ** same as that currently bound to variable pVar, non-zero is returned.
|
|
// ** Otherwise, if the values are not the same or if pExpr is not a simple
|
|
// ** SQL value, zero is returned.
|
|
// **
|
|
// ** If the SQLITE_EnableQPSG flag is set on the database connection, then
|
|
// ** this routine always returns false.
|
|
// */
|
|
func _exprCompareVariable(tls *libc.TLS, pParse uintptr, pVar uintptr, pExpr uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iVar, res, v1 int32
|
|
var pL uintptr
|
|
var _ /* pR at bp+0 */ uintptr
|
|
_, _, _, _ = iVar, pL, res, v1
|
|
res = int32(2)
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_VARIABLE) && int32((*TExpr)(unsafe.Pointer(pVar)).FiColumn) == int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) {
|
|
return 0
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).Fflags&uint64(SQLITE_EnableQPSG) != uint64(0) {
|
|
return int32(2)
|
|
}
|
|
_sqlite3ValueFromExpr(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pExpr, uint8(SQLITE_UTF8), uint8(SQLITE_AFF_BLOB), bp)
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
iVar = int32((*TExpr)(unsafe.Pointer(pVar)).FiColumn)
|
|
_sqlite3VdbeSetVarmask(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, iVar)
|
|
pL = _sqlite3VdbeGetBoundValue(tls, (*TParse)(unsafe.Pointer(pParse)).FpReprepare, iVar, uint8(SQLITE_AFF_BLOB))
|
|
if pL != 0 {
|
|
if Xsqlite3_value_type(tls, pL) == int32(SQLITE_TEXT) {
|
|
Xsqlite3_value_text(tls, pL) /* Make sure the encoding is UTF-8 */
|
|
}
|
|
if _sqlite3MemCompare(tls, pL, **(**uintptr)(__ccgo_up(bp)), uintptr(0)) != 0 {
|
|
v1 = int32(2)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
res = v1
|
|
}
|
|
_sqlite3ValueFree(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
_sqlite3ValueFree(tls, pL)
|
|
}
|
|
return res
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute the two operands of a binary operator.
|
|
// **
|
|
// ** If either operand contains a subquery, then the code strives to
|
|
// ** compute the operand containing the subquery second. If the other
|
|
// ** operand evalutes to NULL, then a jump is made. The address of the
|
|
// ** IsNull operand that does this jump is returned. The caller can use
|
|
// ** this to optimize the computation so as to avoid doing the potentially
|
|
// ** expensive subquery.
|
|
// **
|
|
// ** If no optimization opportunities exist, return 0.
|
|
// */
|
|
func _exprComputeOperands(tls *libc.TLS, pParse uintptr, pExpr uintptr, pR1 uintptr, pR2 uintptr, pFree1 uintptr, pFree2 uintptr) (r int32) {
|
|
var addrIsNull, r1, r2 int32
|
|
var v uintptr
|
|
_, _, _, _ = addrIsNull, r1, r2, v
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
/*
|
|
** If the left operand contains a (possibly expensive) subquery and the
|
|
** right operand does not and the right operation might be NULL,
|
|
** then compute the right operand first and do an IsNull jump if the
|
|
** right operand evalutes to NULL.
|
|
*/
|
|
if _exprEvalRhsFirst(tls, pExpr) != 0 && _sqlite3ExprCanBeNull(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpRight) != 0 {
|
|
r2 = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, pFree2)
|
|
addrIsNull = _sqlite3VdbeAddOp1(tls, v, int32(OP_IsNull), r2)
|
|
} else {
|
|
r2 = 0 /* Silence a false-positive uninit-var warning in MSVC */
|
|
addrIsNull = 0
|
|
}
|
|
r1 = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, pFree1)
|
|
if addrIsNull == 0 {
|
|
/*
|
|
** If the right operand contains a subquery and the left operand does not
|
|
** and the left operand might be NULL, then do an IsNull check
|
|
** check on the left operand before computing the right operand.
|
|
*/
|
|
if (*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pExpr)).FpRight)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subquery)) != uint32(0) && _sqlite3ExprCanBeNull(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft) != 0 {
|
|
addrIsNull = _sqlite3VdbeAddOp1(tls, v, int32(OP_IsNull), r1)
|
|
}
|
|
r2 = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, pFree2)
|
|
}
|
|
**(**int32)(__ccgo_up(pR1)) = r1
|
|
**(**int32)(__ccgo_up(pR2)) = r2
|
|
return addrIsNull
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if it might be advantageous to compute the right operand
|
|
// ** of expression pExpr first, before the left operand.
|
|
// **
|
|
// ** Normally the left operand is computed before the right operand. But if
|
|
// ** the left operand contains a subquery and the right does not, then it
|
|
// ** might be more efficient to compute the right operand first.
|
|
// */
|
|
func _exprEvalRhsFirst(tls *libc.TLS, pExpr uintptr) (r int32) {
|
|
if (*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pExpr)).FpLeft)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subquery)) != uint32(0) && !((*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pExpr)).FpRight)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subquery)) != libc.Uint32FromInt32(0)) {
|
|
return int32(1)
|
|
} else {
|
|
return 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Helper function for exprIsDeterministic().
|
|
// */
|
|
func _exprNodeIsDeterministic(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_FUNCTION) && libc.BoolInt32((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_ConstFunc)) != uint32(0)) == 0 {
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(0)
|
|
return int32(WRC_Abort)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The database opened by the first argument is an auto-vacuum database
|
|
// ** nOrig pages in size containing nFree free pages. Return the expected
|
|
// ** size of the database in pages following an auto-vacuum operation.
|
|
// */
|
|
func _finalDbSize(tls *libc.TLS, pBt uintptr, nOrig TPgno, nFree TPgno) (r TPgno) {
|
|
var nEntry int32
|
|
var nFin, nPtrmap TPgno
|
|
_, _, _ = nEntry, nFin, nPtrmap /* Return value */
|
|
nEntry = libc.Int32FromUint32((*TBtShared)(unsafe.Pointer(pBt)).FusableSize / uint32(5))
|
|
nPtrmap = (nFree - nOrig + _ptrmapPageno(tls, pBt, nOrig) + libc.Uint32FromInt32(nEntry)) / libc.Uint32FromInt32(nEntry)
|
|
nFin = nOrig - nFree - nPtrmap
|
|
if nOrig > libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) && nFin < libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) {
|
|
nFin = nFin - 1
|
|
}
|
|
for _ptrmapPageno(tls, pBt, nFin) == nFin || nFin == libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) {
|
|
nFin = nFin - 1
|
|
}
|
|
return nFin
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE
|
|
// ** is a constant expression and where the term must be true because it
|
|
// ** is part of the AND-connected terms of the expression. For each term
|
|
// ** found, add it to the pConst structure.
|
|
// */
|
|
func _findConstInWhere(tls *libc.TLS, pConst uintptr, pExpr uintptr) {
|
|
var pLeft, pRight uintptr
|
|
_, _ = pLeft, pRight
|
|
if pExpr == uintptr(0) {
|
|
return
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&(*TWhereConst)(unsafe.Pointer(pConst)).FmExcludeOn != uint32(0) {
|
|
return
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AND) {
|
|
_findConstInWhere(tls, pConst, (*TExpr)(unsafe.Pointer(pExpr)).FpRight)
|
|
_findConstInWhere(tls, pConst, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft)
|
|
return
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_EQ) {
|
|
return
|
|
}
|
|
pRight = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
pLeft = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pRight)).Fop) == int32(TK_COLUMN) && _sqlite3ExprIsConstant(tls, (*TWhereConst)(unsafe.Pointer(pConst)).FpParse, pLeft) != 0 {
|
|
_constInsert(tls, pConst, pRight, pLeft, pExpr)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pLeft)).Fop) == int32(TK_COLUMN) && _sqlite3ExprIsConstant(tls, (*TWhereConst)(unsafe.Pointer(pConst)).FpParse, pRight) != 0 {
|
|
_constInsert(tls, pConst, pLeft, pRight, pExpr)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine runs after codeDistinct(). It makes necessary
|
|
// ** adjustments to the OP_OpenEphemeral opcode that the codeDistinct()
|
|
// ** routine made use of. This processing must be done separately since
|
|
// ** sometimes codeDistinct is called before the OP_OpenEphemeral is actually
|
|
// ** laid down.
|
|
// **
|
|
// ** WHERE_DISTINCT_NOOP:
|
|
// ** WHERE_DISTINCT_UNORDERED:
|
|
// **
|
|
// ** No adjustments necessary. This function is a no-op.
|
|
// **
|
|
// ** WHERE_DISTINCT_UNIQUE:
|
|
// **
|
|
// ** The ephemeral table is not needed. So change the
|
|
// ** OP_OpenEphemeral opcode into an OP_Noop.
|
|
// **
|
|
// ** WHERE_DISTINCT_ORDERED:
|
|
// **
|
|
// ** The ephemeral table is not needed. But we do need register
|
|
// ** iVal to be initialized to NULL. So change the OP_OpenEphemeral
|
|
// ** into an OP_Null on the iVal register.
|
|
// */
|
|
func _fixDistinctOpenEph(tls *libc.TLS, pParse uintptr, eTnctType int32, iVal int32, iOpenEphAddr int32) {
|
|
var pOp, v uintptr
|
|
_, _ = pOp, v
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr == 0 && (eTnctType == int32(WHERE_DISTINCT_UNIQUE) || eTnctType == int32(WHERE_DISTINCT_ORDERED)) {
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
_sqlite3VdbeChangeToNoop(tls, v, iOpenEphAddr)
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(_sqlite3VdbeGetOp(tls, v, iOpenEphAddr+int32(1)))).Fopcode) == int32(OP_Explain) {
|
|
_sqlite3VdbeChangeToNoop(tls, v, iOpenEphAddr+int32(1))
|
|
}
|
|
if eTnctType == int32(WHERE_DISTINCT_ORDERED) {
|
|
/* Change the OP_OpenEphemeral to an OP_Null that sets the MEM_Cleared
|
|
** bit on the first register of the previous value. This will cause the
|
|
** OP_Ne added in codeDistinct() to always fail on the first iteration of
|
|
** the loop even if the first row is all NULLs. */
|
|
pOp = _sqlite3VdbeGetOp(tls, v, iOpenEphAddr)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode = uint8(OP_Null)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp1 = int32(1)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp2 = iVal
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called when a row is inserted into or deleted from the
|
|
// ** child table of foreign key constraint pFKey. If an SQL UPDATE is executed
|
|
// ** on the child table of pFKey, this function is invoked twice for each row
|
|
// ** affected - once to "delete" the old row, and then again to "insert" the
|
|
// ** new row.
|
|
// **
|
|
// ** Each time it is called, this function generates VDBE code to locate the
|
|
// ** row in the parent table that corresponds to the row being inserted into
|
|
// ** or deleted from the child table. If the parent row can be found, no
|
|
// ** special action is taken. Otherwise, if the parent row can *not* be
|
|
// ** found in the parent table:
|
|
// **
|
|
// ** Operation | FK type | Action taken
|
|
// ** --------------------------------------------------------------------------
|
|
// ** INSERT immediate Increment the "immediate constraint counter".
|
|
// **
|
|
// ** DELETE immediate Decrement the "immediate constraint counter".
|
|
// **
|
|
// ** INSERT deferred Increment the "deferred constraint counter".
|
|
// **
|
|
// ** DELETE deferred Decrement the "deferred constraint counter".
|
|
// **
|
|
// ** These operations are identified in the comment at the top of this file
|
|
// ** (fkey.c) as "I.1" and "D.1".
|
|
// */
|
|
func _fkLookupParent(tls *libc.TLS, pParse uintptr, iDb int32, pTab uintptr, pIdx uintptr, pFKey uintptr, aiCol uintptr, regData int32, nIncr int32, isIgnore int32) {
|
|
var i, iChild, iCur, iJump, iMustBeInt, iOk, iParent, iReg, nCol, regTemp, regTemp1 int32
|
|
var v uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = i, iChild, iCur, iJump, iMustBeInt, iOk, iParent, iReg, nCol, regTemp, regTemp1, v /* Iterator variable */
|
|
v = _sqlite3GetVdbe(tls, pParse) /* Vdbe to add code to */
|
|
iCur = (*TParse)(unsafe.Pointer(pParse)).FnTab - int32(1) /* Cursor number to use */
|
|
iOk = _sqlite3VdbeMakeLabel(tls, pParse) /* jump here if parent key found */
|
|
/* If nIncr is less than zero, then check at runtime if there are any
|
|
** outstanding constraints to resolve. If there are not, there is no need
|
|
** to check if deleting this row resolves any outstanding violations.
|
|
**
|
|
** Check if any of the key columns in the child table row are NULL. If
|
|
** any are, then the constraint is considered satisfied. No need to
|
|
** search for a matching row in the parent table. */
|
|
if nIncr < 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_FkIfZero), libc.Int32FromUint8((*TFKey)(unsafe.Pointer(pFKey)).FisDeferred), iOk)
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFKey)(unsafe.Pointer(pFKey)).FnCol) {
|
|
break
|
|
}
|
|
iReg = int32(_sqlite3TableColumnToStorage(tls, (*TFKey)(unsafe.Pointer(pFKey)).FpFrom, int16(**(**int32)(__ccgo_up(aiCol + uintptr(i)*4))))) + regData + int32(1)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IsNull), iReg, iOk)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if isIgnore == 0 {
|
|
if pIdx == uintptr(0) { /* Address of MustBeInt instruction */
|
|
regTemp = _sqlite3GetTempReg(tls, pParse)
|
|
/* Invoke MustBeInt to coerce the child key value to an integer (i.e.
|
|
** apply the affinity of the parent key). If this fails, then there
|
|
** is no matching parent key. Before using MustBeInt, make a copy of
|
|
** the value. Otherwise, the value inserted into the child key column
|
|
** will have INTEGER affinity applied to it, which may not be correct. */
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_SCopy), int32(_sqlite3TableColumnToStorage(tls, (*TFKey)(unsafe.Pointer(pFKey)).FpFrom, int16(**(**int32)(__ccgo_up(aiCol)))))+int32(1)+regData, regTemp)
|
|
iMustBeInt = _sqlite3VdbeAddOp2(tls, v, int32(OP_MustBeInt), regTemp, 0)
|
|
/* If the parent table is the same as the child table, and we are about
|
|
** to increment the constraint-counter (i.e. this is an INSERT operation),
|
|
** then check if the row being inserted matches itself. If so, do not
|
|
** increment the constraint-counter. */
|
|
if pTab == (*TFKey)(unsafe.Pointer(pFKey)).FpFrom && nIncr == int32(1) {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Eq), regData, iOk, regTemp)
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(SQLITE_NOTNULL))
|
|
}
|
|
_sqlite3OpenTable(tls, pParse, iCur, iDb, pTab, int32(OP_OpenRead))
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_NotExists), iCur, 0, regTemp)
|
|
_sqlite3VdbeGoto(tls, v, iOk)
|
|
_sqlite3VdbeJumpHere(tls, v, _sqlite3VdbeCurrentAddr(tls, v)-int32(2))
|
|
_sqlite3VdbeJumpHere(tls, v, iMustBeInt)
|
|
_sqlite3ReleaseTempReg(tls, pParse, regTemp)
|
|
} else {
|
|
nCol = (*TFKey)(unsafe.Pointer(pFKey)).FnCol
|
|
regTemp1 = _sqlite3GetTempRange(tls, pParse, nCol)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_OpenRead), iCur, libc.Int32FromUint32((*TIndex)(unsafe.Pointer(pIdx)).Ftnum), iDb)
|
|
_sqlite3VdbeSetP4KeyInfo(tls, pParse, pIdx)
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Copy), int32(_sqlite3TableColumnToStorage(tls, (*TFKey)(unsafe.Pointer(pFKey)).FpFrom, int16(**(**int32)(__ccgo_up(aiCol + uintptr(i)*4)))))+int32(1)+regData, regTemp1+i)
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
/* If the parent table is the same as the child table, and we are about
|
|
** to increment the constraint-counter (i.e. this is an INSERT operation),
|
|
** then check if the row being inserted matches itself. If so, do not
|
|
** increment the constraint-counter.
|
|
**
|
|
** If any of the parent-key values are NULL, then the row cannot match
|
|
** itself. So set JUMPIFNULL to make sure we do the OP_Found if any
|
|
** of the parent-key values are NULL (at this point it is known that
|
|
** none of the child key values are).
|
|
*/
|
|
if pTab == (*TFKey)(unsafe.Pointer(pFKey)).FpFrom && nIncr == int32(1) {
|
|
iJump = _sqlite3VdbeCurrentAddr(tls, v) + nCol + int32(1)
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
iChild = int32(_sqlite3TableColumnToStorage(tls, (*TFKey)(unsafe.Pointer(pFKey)).FpFrom, int16(**(**int32)(__ccgo_up(aiCol + uintptr(i)*4))))) + int32(1) + regData
|
|
iParent = int32(1) + regData
|
|
iParent = iParent + int32(_sqlite3TableColumnToStorage(tls, (*TIndex)(unsafe.Pointer(pIdx)).FpTable, **(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i)*2))))
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i)*2))) == int32((*TTable)(unsafe.Pointer(pTab)).FiPKey) {
|
|
/* The parent key is a composite key that includes the IPK column */
|
|
iParent = regData
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Ne), iChild, iJump, iParent)
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(SQLITE_JUMPIFNULL))
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3VdbeGoto(tls, v, iOk)
|
|
}
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_Affinity), regTemp1, nCol, 0, _sqlite3IndexAffinityStr(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pIdx), nCol)
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_Found), iCur, iOk, regTemp1, nCol)
|
|
_sqlite3ReleaseTempRange(tls, pParse, regTemp1, nCol)
|
|
}
|
|
}
|
|
if !((*TFKey)(unsafe.Pointer(pFKey)).FisDeferred != 0) && !((*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).Fflags&libc.Uint64FromInt32(SQLITE_DeferFKs) != 0) && !((*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0) && !((*TParse)(unsafe.Pointer(pParse)).FisMultiWrite != 0) {
|
|
/* Special case: If this is an INSERT statement that will insert exactly
|
|
** one row into the table, raise a constraint immediately instead of
|
|
** incrementing a counter. This is necessary as the VM code is being
|
|
** generated for will not open a statement transaction. */
|
|
_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))
|
|
} else {
|
|
if nIncr > 0 && libc.Int32FromUint8((*TFKey)(unsafe.Pointer(pFKey)).FisDeferred) == 0 {
|
|
_sqlite3MayAbort(tls, pParse)
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_FkCounter), libc.Int32FromUint8((*TFKey)(unsafe.Pointer(pFKey)).FisDeferred), nIncr)
|
|
}
|
|
_sqlite3VdbeResolveLabel(tls, v, iOk)
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_Close), iCur)
|
|
}
|
|
|
|
func _fts5ApiPhraseNextColumn(tls *libc.TLS, pCtx uintptr, pIter uintptr, piCol uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var pConfig, pCsr uintptr
|
|
var _ /* dummy at bp+4 */ int32
|
|
var _ /* iIncr at bp+0 */ int32
|
|
_, _ = pConfig, pCsr
|
|
pCsr = pCtx
|
|
pConfig = (*TFts5Table)(unsafe.Pointer((*TFts5Cursor)(unsafe.Pointer(pCsr)).Fbase.FpVtab)).FpConfig
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FeDetail == int32(FTS5_DETAIL_COLUMNS) {
|
|
if (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa >= (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fb {
|
|
**(**int32)(__ccgo_up(piCol)) = -int32(1)
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(pIter)) += uintptr(_sqlite3Fts5GetVarint32(tls, (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa, bp))
|
|
**(**int32)(__ccgo_up(piCol)) += **(**int32)(__ccgo_up(bp)) - int32(2)
|
|
}
|
|
} else {
|
|
for int32(1) != 0 {
|
|
if (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa >= (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fb {
|
|
**(**int32)(__ccgo_up(piCol)) = -int32(1)
|
|
return
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up((*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa))) == int32(0x01) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(pIter)) += uintptr(_sqlite3Fts5GetVarint32(tls, (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa, bp+4))
|
|
}
|
|
**(**uintptr)(__ccgo_up(pIter)) += uintptr(int32(1) + _sqlite3Fts5GetVarint32(tls, (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa+1, piCol))
|
|
}
|
|
}
|
|
|
|
func _fts5DlidxExtractFirstRowid(tls *libc.TLS, pBuf uintptr) (r Ti64) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iOff int32
|
|
var _ /* iRowid at bp+0 */ Ti64
|
|
_ = iOff
|
|
iOff = int32(1) + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp+1, bp))
|
|
_sqlite3Fts5GetVarint(tls, (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp+uintptr(iOff), bp)
|
|
return **(**Ti64)(__ccgo_up(bp))
|
|
}
|
|
|
|
func _fts5ExprSynonymAdvanceto(tls *libc.TLS, pTerm uintptr, bDesc int32, piLast uintptr, pRc uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iLast, iRowid Ti64
|
|
var p uintptr
|
|
var rc int32
|
|
var _ /* bEof at bp+0 */ int32
|
|
_, _, _, _ = iLast, iRowid, p, rc
|
|
rc = SQLITE_OK
|
|
iLast = **(**Ti64)(__ccgo_up(piLast))
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
p = pTerm
|
|
for {
|
|
if !(rc == SQLITE_OK && p != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TFts5IndexIter)(unsafe.Pointer((*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)).FbEof) == 0 {
|
|
iRowid = (*TFts5IndexIter)(unsafe.Pointer((*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)).FiRowid
|
|
if bDesc == 0 && iLast > iRowid || bDesc != 0 && iLast < iRowid {
|
|
rc = _sqlite3Fts5IterNextFrom(tls, (*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter, iLast)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TFts5ExprTerm)(unsafe.Pointer(p)).FpSynonym
|
|
}
|
|
if rc != SQLITE_OK {
|
|
**(**int32)(__ccgo_up(pRc)) = rc
|
|
**(**int32)(__ccgo_up(bp)) = int32(1)
|
|
} else {
|
|
**(**Ti64)(__ccgo_up(piLast)) = _fts5ExprSynonymRowid(tls, pTerm, bDesc, bp)
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Argument pTerm must be a synonym iterator. Return the current rowid
|
|
// ** that it points to.
|
|
// */
|
|
func _fts5ExprSynonymRowid(tls *libc.TLS, pTerm uintptr, bDesc int32, pbEof uintptr) (r Ti64) {
|
|
var bRetValid int32
|
|
var iRet, iRowid Ti64
|
|
var p uintptr
|
|
_, _, _, _ = bRetValid, iRet, iRowid, p
|
|
iRet = 0
|
|
bRetValid = 0
|
|
p = pTerm
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if 0 == libc.Int32FromUint8((*TFts5IndexIter)(unsafe.Pointer((*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)).FbEof) {
|
|
iRowid = (*TFts5IndexIter)(unsafe.Pointer((*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)).FiRowid
|
|
if bRetValid == 0 || bDesc != libc.BoolInt32(iRowid < iRet) {
|
|
iRet = iRowid
|
|
bRetValid = int32(1)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TFts5ExprTerm)(unsafe.Pointer(p)).FpSynonym
|
|
}
|
|
if pbEof != 0 && bRetValid == 0 {
|
|
**(**int32)(__ccgo_up(pbEof)) = int32(1)
|
|
}
|
|
return iRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Argument p points to a buffer containing a varint to be interpreted as a
|
|
// ** position list size field. Read the varint and return the number of bytes
|
|
// ** read. Before returning, set *pnSz to the number of bytes in the position
|
|
// ** list, and *pbDel to true if the delete flag is set, or false otherwise.
|
|
// */
|
|
func _fts5GetPoslistSize(tls *libc.TLS, p uintptr, pnSz uintptr, pbDel uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var n, v1 int32
|
|
var _ /* nSz at bp+0 */ int32
|
|
_, _ = n, v1
|
|
n = 0
|
|
v1 = n
|
|
n = n + 1
|
|
**(**int32)(__ccgo_up(bp)) = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(p + uintptr(v1))))
|
|
if **(**int32)(__ccgo_up(bp))&int32(0x80) != 0 {
|
|
n = n - 1
|
|
n = n + _sqlite3Fts5GetVarint32(tls, p+uintptr(n), bp)
|
|
}
|
|
**(**int32)(__ccgo_up(pnSz)) = **(**int32)(__ccgo_up(bp)) / int32(2)
|
|
**(**int32)(__ccgo_up(pbDel)) = **(**int32)(__ccgo_up(bp)) & int32(0x0001)
|
|
return n
|
|
}
|
|
|
|
func _fts5GetU16(tls *libc.TLS, aIn uintptr) (r Tu16) {
|
|
return libc.Uint16FromInt32(libc.Int32FromUint16(uint16(**(**Tu8)(__ccgo_up(aIn))))<<int32(8) + libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aIn + 1))))
|
|
}
|
|
|
|
func _fts5HashKey(tls *libc.TLS, nSlot int32, p uintptr, n int32) (r uint32) {
|
|
var h uint32
|
|
var i int32
|
|
_, _ = h, i
|
|
h = uint32(13)
|
|
i = n - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
h = h<<int32(3) ^ h ^ uint32(**(**Tu8)(__ccgo_up(p + uintptr(i))))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
return h % libc.Uint32FromInt32(nSlot)
|
|
}
|
|
|
|
func _fts5HashKey2(tls *libc.TLS, nSlot int32, b Tu8, p uintptr, n int32) (r uint32) {
|
|
var h uint32
|
|
var i int32
|
|
_, _ = h, i
|
|
h = uint32(13)
|
|
i = n - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
h = h<<int32(3) ^ h ^ uint32(**(**Tu8)(__ccgo_up(p + uintptr(i))))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
h = h<<int32(3) ^ h ^ uint32(b)
|
|
return h % libc.Uint32FromInt32(nSlot)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check that:
|
|
// **
|
|
// ** 1) All leaves of pSeg between iFirst and iLast (inclusive) exist and
|
|
// ** contain zero terms.
|
|
// ** 2) All leaves of pSeg between iNoRowid and iLast (inclusive) exist and
|
|
// ** contain zero rowids.
|
|
// */
|
|
func _fts5IndexIntegrityCheckEmpty(tls *libc.TLS, p uintptr, pSeg uintptr, iFirst int32, iNoRowid int32, iLast int32) {
|
|
var i int32
|
|
var pLeaf uintptr
|
|
_, _ = i, pLeaf
|
|
/* Now check that the iter.nEmpty leaves following the current leaf
|
|
** (a) exist and (b) contain no terms. */
|
|
i = iFirst
|
|
for {
|
|
if !((*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK && i <= iLast) {
|
|
break
|
|
}
|
|
pLeaf = _fts5DataRead(tls, p, 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(i))
|
|
if pLeaf != 0 {
|
|
if !((*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf >= (*TFts5Data)(unsafe.Pointer(pLeaf)).Fnn) || i >= iNoRowid && 0 != libc.Int32FromUint16(_fts5GetU16(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp)) {
|
|
_fts5IndexCorruptRowid(tls, p, 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(i))
|
|
}
|
|
}
|
|
_fts5DataRelease(tls, pLeaf)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
func _fts5IndexPrepareStmt(tls *libc.TLS, p uintptr, ppStmt uintptr, zSql uintptr) (r int32) {
|
|
var rc, v1 int32
|
|
_, _ = rc, v1
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
if zSql != 0 {
|
|
rc = Xsqlite3_prepare_v3(tls, (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).Fdb, zSql, -int32(1), libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_PREPARE_PERSISTENT)|libc.Int32FromInt32(SQLITE_PREPARE_NO_VTAB)), ppStmt, uintptr(0))
|
|
/* If this prepare() call fails with SQLITE_ERROR, then one of the
|
|
** %_idx or %_data tables has been removed or modified. Call this
|
|
** corruption. */
|
|
if rc == int32(SQLITE_ERROR) {
|
|
v1 = int32(SQLITE_CORRUPT)
|
|
} else {
|
|
v1 = rc
|
|
}
|
|
(*TFts5Index)(unsafe.Pointer(p)).Frc = v1
|
|
} else {
|
|
(*TFts5Index)(unsafe.Pointer(p)).Frc = int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
Xsqlite3_free(tls, zSql)
|
|
return (*TFts5Index)(unsafe.Pointer(p)).Frc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Buffer pPg contains a page of a tombstone hash table - one of nPg pages
|
|
// ** associated with the same segment. This function adds rowid iRowid to
|
|
// ** the hash table. The caller is required to guarantee that there is at
|
|
// ** least one free slot on the page.
|
|
// **
|
|
// ** If parameter bForce is false and the hash table is deemed to be full
|
|
// ** (more than half of the slots are occupied), then non-zero is returned
|
|
// ** and iRowid not inserted. Or, if bForce is true or if the hash table page
|
|
// ** is not full, iRowid is inserted and zero returned.
|
|
// */
|
|
func _fts5IndexTombstoneAddToPage(tls *libc.TLS, pPg uintptr, bForce int32, nPg int32, iRowid Tu64) (r int32) {
|
|
var aSlot, aSlot1 uintptr
|
|
var iSlot, nCollide, nElem, nSlot, szKey, v1, v2, v3 int32
|
|
_, _, _, _, _, _, _, _, _, _ = aSlot, aSlot1, iSlot, nCollide, nElem, nSlot, szKey, v1, v2, v3
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pPg)).Fp))) == int32(4) {
|
|
v1 = int32(4)
|
|
} else {
|
|
v1 = int32(8)
|
|
}
|
|
szKey = v1
|
|
if (*TFts5Data)(unsafe.Pointer(pPg)).Fnn > int32(16) {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pPg)).Fp))) == int32(4) {
|
|
v3 = int32(4)
|
|
} else {
|
|
v3 = int32(8)
|
|
}
|
|
v2 = ((*TFts5Data)(unsafe.Pointer(pPg)).Fnn - int32(8)) / v3
|
|
} else {
|
|
v2 = int32(1)
|
|
}
|
|
nSlot = v2
|
|
nElem = libc.Int32FromUint32(_fts5GetU32(tls, (*TFts5Data)(unsafe.Pointer(pPg)).Fp+4))
|
|
iSlot = libc.Int32FromUint64(iRowid / libc.Uint64FromInt32(nPg) % libc.Uint64FromInt32(nSlot))
|
|
nCollide = nSlot
|
|
if szKey == int32(4) && iRowid > uint64(0xFFFFFFFF) {
|
|
return int32(2)
|
|
}
|
|
if iRowid == uint64(0) {
|
|
**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pPg)).Fp + 1)) = uint8(0x01)
|
|
return 0
|
|
}
|
|
if bForce == 0 && nElem >= nSlot/int32(2) {
|
|
return int32(1)
|
|
}
|
|
_fts5PutU32(tls, (*TFts5Data)(unsafe.Pointer(pPg)).Fp+4, libc.Uint32FromInt32(nElem+int32(1)))
|
|
if szKey == int32(4) {
|
|
aSlot = (*TFts5Data)(unsafe.Pointer(pPg)).Fp + 8
|
|
for **(**Tu32)(__ccgo_up(aSlot + uintptr(iSlot)*4)) != 0 {
|
|
iSlot = (iSlot + int32(1)) % nSlot
|
|
v1 = nCollide
|
|
nCollide = nCollide - 1
|
|
if v1 == 0 {
|
|
return 0
|
|
}
|
|
}
|
|
_fts5PutU32(tls, aSlot+uintptr(iSlot)*4, uint32(iRowid))
|
|
} else {
|
|
aSlot1 = (*TFts5Data)(unsafe.Pointer(pPg)).Fp + 8
|
|
for **(**Tu64)(__ccgo_up(aSlot1 + uintptr(iSlot)*8)) != 0 {
|
|
iSlot = (iSlot + int32(1)) % nSlot
|
|
v1 = nCollide
|
|
nCollide = nCollide - 1
|
|
if v1 == 0 {
|
|
return 0
|
|
}
|
|
}
|
|
_fts5PutU64(tls, aSlot1+uintptr(iSlot)*8, iRowid)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Query a single tombstone hash table for rowid iRowid. Return true if
|
|
// ** it is found or false otherwise. The tombstone hash table is one of
|
|
// ** nHashTable tables.
|
|
// */
|
|
func _fts5IndexTombstoneQuery(tls *libc.TLS, pHash uintptr, nHashTable int32, iRowid Tu64) (r int32) {
|
|
var aSlot, aSlot1 uintptr
|
|
var iSlot, nCollide, nSlot, szKey, v1, v2, v3 int32
|
|
_, _, _, _, _, _, _, _, _ = aSlot, aSlot1, iSlot, nCollide, nSlot, szKey, v1, v2, v3
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pHash)).Fp))) == int32(4) {
|
|
v1 = int32(4)
|
|
} else {
|
|
v1 = int32(8)
|
|
}
|
|
szKey = v1
|
|
if (*TFts5Data)(unsafe.Pointer(pHash)).Fnn > int32(16) {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pHash)).Fp))) == int32(4) {
|
|
v3 = int32(4)
|
|
} else {
|
|
v3 = int32(8)
|
|
}
|
|
v2 = ((*TFts5Data)(unsafe.Pointer(pHash)).Fnn - int32(8)) / v3
|
|
} else {
|
|
v2 = int32(1)
|
|
}
|
|
nSlot = v2
|
|
iSlot = libc.Int32FromUint64(iRowid / libc.Uint64FromInt32(nHashTable) % libc.Uint64FromInt32(nSlot))
|
|
nCollide = nSlot
|
|
if iRowid == uint64(0) {
|
|
return libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pHash)).Fp + 1)))
|
|
} else {
|
|
if szKey == int32(4) {
|
|
aSlot = (*TFts5Data)(unsafe.Pointer(pHash)).Fp + 8
|
|
for **(**Tu32)(__ccgo_up(aSlot + uintptr(iSlot)*4)) != 0 {
|
|
if uint64(_fts5GetU32(tls, aSlot+uintptr(iSlot)*4)) == iRowid {
|
|
return int32(1)
|
|
}
|
|
v1 = nCollide
|
|
nCollide = nCollide - 1
|
|
if v1 == 0 {
|
|
break
|
|
}
|
|
iSlot = (iSlot + int32(1)) % nSlot
|
|
}
|
|
} else {
|
|
aSlot1 = (*TFts5Data)(unsafe.Pointer(pHash)).Fp + 8
|
|
for **(**Tu64)(__ccgo_up(aSlot1 + uintptr(iSlot)*8)) != 0 {
|
|
if _fts5GetU64(tls, aSlot1+uintptr(iSlot)*8) == iRowid {
|
|
return int32(1)
|
|
}
|
|
v1 = nCollide
|
|
nCollide = nCollide - 1
|
|
if v1 == 0 {
|
|
break
|
|
}
|
|
iSlot = (iSlot + int32(1)) % nSlot
|
|
}
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func _fts5NextRowid(tls *libc.TLS, pBuf uintptr, piOff uintptr, piRowid uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i int32
|
|
var v1 uintptr
|
|
var _ /* iVal at bp+0 */ Tu64
|
|
_, _ = i, v1
|
|
i = **(**int32)(__ccgo_up(piOff))
|
|
if i >= (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn {
|
|
**(**int32)(__ccgo_up(piOff)) = -int32(1)
|
|
} else {
|
|
**(**int32)(__ccgo_up(piOff)) = i + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp+uintptr(i), bp))
|
|
v1 = piRowid
|
|
*(*Ti64)(unsafe.Pointer(v1)) = Ti64(uint64(*(*Ti64)(unsafe.Pointer(v1))) + **(**Tu64)(__ccgo_up(bp)))
|
|
}
|
|
}
|
|
|
|
func _fts5ParseAlloc(tls *libc.TLS, t Tu64) (r uintptr) {
|
|
return Xsqlite3_malloc64(tls, libc.Uint64FromInt64(libc.Int64FromUint64(t)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the size of the prefix, in bytes, that buffer
|
|
// ** (pNew/<length-unknown>) shares with buffer (pOld/nOld).
|
|
// **
|
|
// ** Buffer (pNew/<length-unknown>) is guaranteed to be greater
|
|
// ** than buffer (pOld/nOld).
|
|
// */
|
|
func _fts5PrefixCompress(tls *libc.TLS, nOld int32, pOld uintptr, pNew uintptr) (r int32) {
|
|
var i int32
|
|
_ = i
|
|
i = 0
|
|
for {
|
|
if !(i < nOld) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pOld + uintptr(i)))) != libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pNew + uintptr(i)))) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return i
|
|
}
|
|
|
|
func _fts5PutU16(tls *libc.TLS, aOut uintptr, iVal Tu16) {
|
|
**(**Tu8)(__ccgo_up(aOut)) = libc.Uint8FromInt32(libc.Int32FromUint16(iVal) >> libc.Int32FromInt32(8))
|
|
**(**Tu8)(__ccgo_up(aOut + 1)) = libc.Uint8FromInt32(libc.Int32FromUint16(iVal) & libc.Int32FromInt32(0xFF))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Fts5SegIter.iLeafOffset currently points to the first byte of a
|
|
// ** position-list size field. Read the value of the field and store it
|
|
// ** in the following variables:
|
|
// **
|
|
// ** Fts5SegIter.nPos
|
|
// ** Fts5SegIter.bDel
|
|
// **
|
|
// ** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the
|
|
// ** position list content (if any).
|
|
// */
|
|
func _fts5SegIterLoadNPos(tls *libc.TLS, p uintptr, pIter uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iEod, iOff, v1 int32
|
|
var _ /* nSz at bp+0 */ int32
|
|
_, _, _ = iEod, iOff, v1
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
iOff = int32((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset) /* Offset to read at */
|
|
if (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).FeDetail == int32(FTS5_DETAIL_NONE) {
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist < (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf {
|
|
v1 = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist
|
|
} else {
|
|
v1 = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf
|
|
}
|
|
iEod = v1
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FbDel = uint8(0)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FnPos = int32(1)
|
|
if iOff < iEod && libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp + uintptr(iOff)))) == 0 {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FbDel = uint8(1)
|
|
iOff = iOff + 1
|
|
if iOff < iEod && libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp + uintptr(iOff)))) == 0 {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FnPos = int32(1)
|
|
iOff = iOff + 1
|
|
} else {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FnPos = 0
|
|
}
|
|
}
|
|
} else {
|
|
v1 = iOff
|
|
iOff = iOff + 1
|
|
**(**int32)(__ccgo_up(bp)) = libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp + uintptr(v1))))
|
|
if **(**int32)(__ccgo_up(bp))&int32(0x80) != 0 {
|
|
iOff = iOff - 1
|
|
iOff = iOff + _sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp+uintptr(iOff), bp)
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FbDel = libc.Uint8FromInt32(**(**int32)(__ccgo_up(bp)) & libc.Int32FromInt32(0x0001))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FnPos = **(**int32)(__ccgo_up(bp)) >> int32(1)
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(iOff)
|
|
}
|
|
}
|
|
|
|
func _fts5UsePatternMatch(tls *libc.TLS, pConfig uintptr, p uintptr) (r int32) {
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).Ft.FePattern == int32(FTS5_PATTERN_GLOB) && libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) == int32(FTS5_PATTERN_GLOB) {
|
|
return int32(1)
|
|
}
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).Ft.FePattern == int32(FTS5_PATTERN_LIKE) && (libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) == int32(FTS5_PATTERN_LIKE) || libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) == int32(FTS5_PATTERN_GLOB)) {
|
|
return int32(1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the xBestIndex method.
|
|
// **
|
|
// ** Only constraints of the form:
|
|
// **
|
|
// ** term <= ?
|
|
// ** term == ?
|
|
// ** term >= ?
|
|
// **
|
|
// ** are interpreted. Less-than and less-than-or-equal are treated
|
|
// ** identically, as are greater-than and greater-than-or-equal.
|
|
// */
|
|
func _fts5VocabBestIndexMethod(tls *libc.TLS, pUnused uintptr, pInfo uintptr) (r int32) {
|
|
var i, iTermEq, iTermGe, iTermLe, idxNum, nArg, v2 int32
|
|
var p uintptr
|
|
_, _, _, _, _, _, _, _ = i, iTermEq, iTermGe, iTermLe, idxNum, nArg, p, v2
|
|
iTermEq = -int32(1)
|
|
iTermGe = -int32(1)
|
|
iTermLe = -int32(1)
|
|
idxNum = libc.Int32FromUint64((*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FcolUsed)
|
|
nArg = 0
|
|
_ = pUnused
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FnConstraint) {
|
|
break
|
|
}
|
|
p = (*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FaConstraint + uintptr(i)*12
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fusable) == 0 {
|
|
goto _1
|
|
}
|
|
if (*Tsqlite3_index_constraint)(unsafe.Pointer(p)).FiColumn == 0 { /* term column */
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) == int32(SQLITE_INDEX_CONSTRAINT_EQ) {
|
|
iTermEq = i
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) == int32(SQLITE_INDEX_CONSTRAINT_LE) {
|
|
iTermLe = i
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) == int32(SQLITE_INDEX_CONSTRAINT_LT) {
|
|
iTermLe = i
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) == int32(SQLITE_INDEX_CONSTRAINT_GE) {
|
|
iTermGe = i
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(p)).Fop) == int32(SQLITE_INDEX_CONSTRAINT_GT) {
|
|
iTermGe = i
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if iTermEq >= 0 {
|
|
idxNum = idxNum | int32(FTS5_VOCAB_TERM_EQ)
|
|
nArg = nArg + 1
|
|
v2 = nArg
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FaConstraintUsage + uintptr(iTermEq)*8))).FargvIndex = v2
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FestimatedCost = libc.Float64FromInt32(100)
|
|
} else {
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FestimatedCost = libc.Float64FromInt32(1000000)
|
|
if iTermGe >= 0 {
|
|
idxNum = idxNum | int32(FTS5_VOCAB_TERM_GE)
|
|
nArg = nArg + 1
|
|
v2 = nArg
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FaConstraintUsage + uintptr(iTermGe)*8))).FargvIndex = v2
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FestimatedCost = (*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FestimatedCost / libc.Float64FromInt32(2)
|
|
}
|
|
if iTermLe >= 0 {
|
|
idxNum = idxNum | int32(FTS5_VOCAB_TERM_LE)
|
|
nArg = nArg + 1
|
|
v2 = nArg
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FaConstraintUsage + uintptr(iTermLe)*8))).FargvIndex = v2
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FestimatedCost = (*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FestimatedCost / libc.Float64FromInt32(2)
|
|
}
|
|
}
|
|
/* This virtual table always delivers results in ascending order of
|
|
** the "term" column (column 0). So if the user has requested this
|
|
** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the
|
|
** sqlite3_index_info.orderByConsumed flag to tell the core the results
|
|
** are already in sorted order. */
|
|
if (*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FnOrderBy == int32(1) && (**(**Tsqlite3_index_orderby)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FaOrderBy))).FiColumn == 0 && libc.Int32FromUint8((**(**Tsqlite3_index_orderby)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FaOrderBy))).Fdesc) == 0 {
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).ForderByConsumed = int32(1)
|
|
}
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pInfo)).FidxNum = idxNum
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* The following function deletes the "minor type" or semantic value
|
|
// ** associated with a symbol. The symbol can be either a terminal
|
|
// ** or nonterminal. "fts5yymajor" is the symbol code, and "fts5yypminor" is
|
|
// ** a pointer to the value to be deleted. The code used to do the
|
|
// ** deletions is derived from the %destructor and/or %token_destructor
|
|
// ** directives of the input grammar.
|
|
// */
|
|
func _fts5yy_destructor(tls *libc.TLS, fts5yypParser uintptr, fts5yymajor uint8, fts5yypminor uintptr) {
|
|
var pParse uintptr
|
|
_ = pParse
|
|
pParse = (*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).FpParse
|
|
switch libc.Int32FromUint8(fts5yymajor) {
|
|
/* Here is inserted the actions which take place when a
|
|
** terminal or non-terminal is destroyed. This can happen
|
|
** when the symbol is popped from the stack during a
|
|
** reduce or during error processing or when a parser is
|
|
** being destroyed before it is finished parsing.
|
|
**
|
|
** Note: during a reduce, the only symbols destroyed are those
|
|
** which appear on the RHS of the rule, but which are *not* used
|
|
** inside the C code.
|
|
*/
|
|
/********* Begin destructor definitions ***************************************/
|
|
case int32(16): /* input */
|
|
_ = pParse
|
|
case int32(17): /* expr */
|
|
fallthrough
|
|
case int32(18): /* cnearset */
|
|
fallthrough
|
|
case int32(19): /* exprlist */
|
|
_sqlite3Fts5ParseNodeFree(tls, *(*uintptr)(unsafe.Pointer(fts5yypminor)))
|
|
case int32(20): /* colset */
|
|
fallthrough
|
|
case int32(21): /* colsetlist */
|
|
Xsqlite3_free(tls, *(*uintptr)(unsafe.Pointer(fts5yypminor)))
|
|
case int32(22): /* nearset */
|
|
fallthrough
|
|
case int32(23): /* nearphrases */
|
|
_sqlite3Fts5ParseNearsetFree(tls, *(*uintptr)(unsafe.Pointer(fts5yypminor)))
|
|
case int32(24): /* phrase */
|
|
_sqlite3Fts5ParsePhraseFree(tls, *(*uintptr)(unsafe.Pointer(fts5yypminor)))
|
|
break
|
|
/********* End destructor definitions *****************************************/
|
|
fallthrough
|
|
default:
|
|
break /* If no destructor action specified: do nothing */
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find the appropriate action for a parser given the non-terminal
|
|
// ** look-ahead token iLookAhead.
|
|
// */
|
|
func _fts5yy_find_reduce_action(tls *libc.TLS, stateno uint8, iLookAhead uint8) (r uint8) {
|
|
var i int32
|
|
_ = i
|
|
i = int32(_fts5yy_reduce_ofst[stateno])
|
|
i = i + libc.Int32FromUint8(iLookAhead)
|
|
return _fts5yy_action[i]
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find the appropriate action for a parser given the terminal
|
|
// ** look-ahead token iLookAhead.
|
|
// */
|
|
func _fts5yy_find_shift_action(tls *libc.TLS, iLookAhead uint8, stateno uint8) (r uint8) {
|
|
var i int32
|
|
_ = i
|
|
if libc.Int32FromUint8(stateno) > int32(fts5YY_MAX_SHIFT) {
|
|
return stateno
|
|
}
|
|
for cond := true; cond; cond = int32(1) != 0 {
|
|
i = libc.Int32FromUint8(_fts5yy_shift_ofst[stateno])
|
|
i = i + libc.Int32FromUint8(iLookAhead)
|
|
if libc.Int32FromUint8(_fts5yy_lookahead[i]) != libc.Int32FromUint8(iLookAhead) {
|
|
return _fts5yy_default[stateno]
|
|
} else {
|
|
return _fts5yy_action[i]
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Insert all segments and events for polygon pPoly.
|
|
// */
|
|
func _geopolyAddSegments(tls *libc.TLS, p uintptr, pPoly uintptr, side uint8) {
|
|
var i uint32
|
|
var x uintptr
|
|
_, _ = i, x
|
|
i = uint32(0)
|
|
for {
|
|
if !(i < libc.Uint32FromInt32((*TGeoPoly)(unsafe.Pointer(pPoly)).FnVertex)-uint32(1)) {
|
|
break
|
|
}
|
|
x = pPoly + 8 + uintptr(i*uint32(2))*4
|
|
_geopolyAddOneSegment(tls, p, **(**TGeoCoord)(__ccgo_up(x)), **(**TGeoCoord)(__ccgo_up(x + 1*4)), **(**TGeoCoord)(__ccgo_up(x + 2*4)), **(**TGeoCoord)(__ccgo_up(x + 3*4)), side, i)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
x = pPoly + 8 + uintptr(i*uint32(2))*4
|
|
_geopolyAddOneSegment(tls, p, **(**TGeoCoord)(__ccgo_up(x)), **(**TGeoCoord)(__ccgo_up(x + 1*4)), **(**TGeoCoord)(__ccgo_up(pPoly + 8)), **(**TGeoCoord)(__ccgo_up(pPoly + 8 + 1*4)), side, i)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Get a page from the pager and initialize it.
|
|
// */
|
|
func _getAndInitPage(tls *libc.TLS, pBt uintptr, pgno TPgno, ppPage uintptr, bReadOnly int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var pPage uintptr
|
|
var rc int32
|
|
var _ /* pDbPage at bp+0 */ uintptr
|
|
_, _ = pPage, rc
|
|
if pgno > _btreePagecount(tls, pBt) {
|
|
**(**uintptr)(__ccgo_up(ppPage)) = uintptr(0)
|
|
return _sqlite3CorruptError(tls, int32(75618))
|
|
}
|
|
rc = _sqlite3PagerGet(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, pgno, bp, bReadOnly)
|
|
if rc != 0 {
|
|
**(**uintptr)(__ccgo_up(ppPage)) = uintptr(0)
|
|
return rc
|
|
}
|
|
pPage = _sqlite3PagerGetExtra(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
if libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FisInit) == 0 {
|
|
_btreePageFromDbPage(tls, **(**uintptr)(__ccgo_up(bp)), pgno, pBt)
|
|
rc = _btreeInitPage(tls, pPage)
|
|
if rc != SQLITE_OK {
|
|
_releasePage(tls, pPage)
|
|
**(**uintptr)(__ccgo_up(ppPage)) = uintptr(0)
|
|
return rc
|
|
}
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppPage)) = pPage
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** For a single cell on a btree page, compute the number of bytes of
|
|
// ** content (payload) stored on that page. That is to say, compute the
|
|
// ** number of bytes of content not found on overflow pages.
|
|
// */
|
|
func _getLocalPayload(tls *libc.TLS, nUsable int32, flags Tu8, nTotal int32) (r int32) {
|
|
var nLocal, nMaxLocal, nMinLocal int32
|
|
_, _, _ = nLocal, nMaxLocal, nMinLocal
|
|
if libc.Int32FromUint8(flags) == int32(0x0D) { /* Table leaf node */
|
|
nMinLocal = (nUsable-int32(12))*int32(32)/int32(255) - int32(23)
|
|
nMaxLocal = nUsable - int32(35)
|
|
} else { /* Index interior and leaf nodes */
|
|
nMinLocal = (nUsable-int32(12))*int32(32)/int32(255) - int32(23)
|
|
nMaxLocal = (nUsable-int32(12))*int32(64)/int32(255) - int32(23)
|
|
}
|
|
nLocal = nMinLocal + (nTotal-nMinLocal)%(nUsable-int32(4))
|
|
if nLocal > nMaxLocal {
|
|
nLocal = nMinLocal
|
|
}
|
|
return nLocal
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return non-zero if the bit in the IntegrityCk.aPgRef[] array that
|
|
// ** corresponds to page iPg is already set.
|
|
// */
|
|
func _getPageReferenced(tls *libc.TLS, pCheck uintptr, iPg TPgno) (r int32) {
|
|
return libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TIntegrityCk)(unsafe.Pointer(pCheck)).FaPgRef + uintptr(iPg/uint32(8))))) & (int32(1) << (iPg & uint32(0x07)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called after transitioning from PAGER_UNLOCK to
|
|
// ** PAGER_SHARED state. It tests if there is a hot journal present in
|
|
// ** the file-system for the given pager. A hot journal is one that
|
|
// ** needs to be played back. According to this function, a hot-journal
|
|
// ** file exists if the following criteria are met:
|
|
// **
|
|
// ** * The journal file exists in the file system, and
|
|
// ** * No process holds a RESERVED or greater lock on the database file, and
|
|
// ** * The database file itself is greater than 0 bytes in size, and
|
|
// ** * The first byte of the journal file exists and is not 0x00.
|
|
// **
|
|
// ** If the current size of the database file is 0 but a journal file
|
|
// ** exists, that is probably an old journal left over from a prior
|
|
// ** database with the same name. In this case the journal file is
|
|
// ** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
|
|
// ** is returned.
|
|
// **
|
|
// ** This routine does not check if there is a super-journal filename
|
|
// ** at the end of the file. If there is, and that super-journal file
|
|
// ** does not exist, then the journal file is not really hot. In this
|
|
// ** case this routine will return a false-positive. The pager_playback()
|
|
// ** routine will discover that the journal file is not really hot and
|
|
// ** will not roll it back.
|
|
// **
|
|
// ** If a hot-journal file is found to exist, *pExists is set to 1 and
|
|
// ** SQLITE_OK returned. If no hot-journal file is present, *pExists is
|
|
// ** set to 0 and SQLITE_OK returned. If an IO error occurs while trying
|
|
// ** to determine whether or not a hot-journal file exists, the IO error
|
|
// ** code is returned and the value of *pExists is undefined.
|
|
// */
|
|
func _hasHotJournal(tls *libc.TLS, pPager uintptr, pExists uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var jrnlOpen, rc int32
|
|
var pVfs uintptr
|
|
var _ /* exists at bp+0 */ int32
|
|
var _ /* f at bp+12 */ int32
|
|
var _ /* first at bp+16 */ Tu8
|
|
var _ /* locked at bp+4 */ int32
|
|
var _ /* nPage at bp+8 */ TPgno
|
|
_, _, _ = jrnlOpen, pVfs, rc
|
|
pVfs = (*TPager)(unsafe.Pointer(pPager)).FpVfs
|
|
rc = SQLITE_OK /* Return code */
|
|
**(**int32)(__ccgo_up(bp)) = int32(1) /* True if a journal file is present */
|
|
jrnlOpen = libc.BoolInt32(!!((*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != libc.UintptrFromInt32(0)))
|
|
**(**int32)(__ccgo_up(pExists)) = 0
|
|
if !(jrnlOpen != 0) {
|
|
rc = _sqlite3OsAccess(tls, pVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, SQLITE_ACCESS_EXISTS, bp)
|
|
}
|
|
if rc == SQLITE_OK && **(**int32)(__ccgo_up(bp)) != 0 {
|
|
**(**int32)(__ccgo_up(bp + 4)) = 0 /* True if some process holds a RESERVED lock */
|
|
/* Race condition here: Another process might have been holding the
|
|
** the RESERVED lock and have a journal open at the sqlite3OsAccess()
|
|
** call above, but then delete the journal and drop the lock before
|
|
** we get to the following sqlite3OsCheckReservedLock() call. If that
|
|
** is the case, this routine might think there is a hot journal when
|
|
** in fact there is none. This results in a false-positive which will
|
|
** be dealt with by the playback routine. Ticket #3883.
|
|
*/
|
|
rc = _sqlite3OsCheckReservedLock(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, bp+4)
|
|
if rc == SQLITE_OK && !(**(**int32)(__ccgo_up(bp + 4)) != 0) { /* Number of pages in database file */
|
|
rc = _pagerPagecount(tls, pPager, bp+8)
|
|
if rc == SQLITE_OK {
|
|
/* If the database is zero pages in size, that means that either (1) the
|
|
** journal is a remnant from a prior database with the same name where
|
|
** the database file but not the journal was deleted, or (2) the initial
|
|
** transaction that populates a new database is being rolled back.
|
|
** In either case, the journal file can be deleted. However, take care
|
|
** not to delete the journal file if it is already open due to
|
|
** journal_mode=PERSIST.
|
|
*/
|
|
if **(**TPgno)(__ccgo_up(bp + 8)) == uint32(0) && !(jrnlOpen != 0) {
|
|
_sqlite3BeginBenignMalloc(tls)
|
|
if _pagerLockDb(tls, pPager, int32(RESERVED_LOCK)) == SQLITE_OK {
|
|
_sqlite3OsDelete(tls, pVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, 0)
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0) {
|
|
_pagerUnlockDb(tls, pPager, int32(SHARED_LOCK))
|
|
}
|
|
}
|
|
_sqlite3EndBenignMalloc(tls)
|
|
} else {
|
|
/* The journal file exists and no other connection has a reserved
|
|
** or greater lock on the database file. Now check that there is
|
|
** at least one non-zero bytes at the start of the journal file.
|
|
** If there is, then we consider this journal to be hot. If not,
|
|
** it can be ignored.
|
|
*/
|
|
if !(jrnlOpen != 0) {
|
|
**(**int32)(__ccgo_up(bp + 12)) = libc.Int32FromInt32(SQLITE_OPEN_READONLY) | libc.Int32FromInt32(SQLITE_OPEN_MAIN_JOURNAL)
|
|
rc = _sqlite3OsOpen(tls, pVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, (*TPager)(unsafe.Pointer(pPager)).Fjfd, **(**int32)(__ccgo_up(bp + 12)), bp+12)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
**(**Tu8)(__ccgo_up(bp + 16)) = uint8(0)
|
|
rc = _sqlite3OsRead(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, bp+16, int32(1), 0)
|
|
if rc == libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(2)<<libc.Int32FromInt32(8) {
|
|
rc = SQLITE_OK
|
|
}
|
|
if !(jrnlOpen != 0) {
|
|
_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
|
|
}
|
|
**(**int32)(__ccgo_up(pExists)) = libc.BoolInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(bp + 16))) != 0)
|
|
} else {
|
|
if rc == int32(SQLITE_CANTOPEN) {
|
|
/* If we cannot open the rollback journal file in order to see if
|
|
** it has a zero header, that might be due to an I/O error, or
|
|
** it might be due to the race condition described above and in
|
|
** ticket #3883. Either way, assume that the journal is hot.
|
|
** This might be a false positive. But if it is, then the
|
|
** automatic journal playback and recovery mechanism will deal
|
|
** with it under an EXCLUSIVE lock where we do not need to
|
|
** worry so much with race conditions.
|
|
*/
|
|
**(**int32)(__ccgo_up(pExists)) = int32(1)
|
|
rc = SQLITE_OK
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** A lists of all unixInodeInfo objects.
|
|
// **
|
|
// ** Must hold unixBigLock in order to read or write this variable.
|
|
// */
|
|
var _inodeList = uintptr(0)
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called before modifying the contents of a table
|
|
// ** to invalidate any incrblob cursors that are open on the
|
|
// ** row or one of the rows being modified.
|
|
// **
|
|
// ** If argument isClearTable is true, then the entire contents of the
|
|
// ** table is about to be deleted. In this case invalidate all incrblob
|
|
// ** cursors open on any row within the table with root-page pgnoRoot.
|
|
// **
|
|
// ** Otherwise, if argument isClearTable is false, then the row with
|
|
// ** rowid iRow is being replaced or deleted. In this case invalidate
|
|
// ** only those incrblob cursors open on that specific row.
|
|
// */
|
|
func _invalidateIncrblobCursors(tls *libc.TLS, pBtree uintptr, pgnoRoot TPgno, iRow Ti64, isClearTable int32) {
|
|
var p uintptr
|
|
_ = p
|
|
(*TBtree)(unsafe.Pointer(pBtree)).FhasIncrblobCur = uint8(0)
|
|
p = (*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(pBtree)).FpBt)).FpCursor
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(p)).FcurFlags)&int32(BTCF_Incrblob) != 0 {
|
|
(*TBtree)(unsafe.Pointer(pBtree)).FhasIncrblobCur = uint8(1)
|
|
if (*TBtCursor)(unsafe.Pointer(p)).FpgnoRoot == pgnoRoot && (isClearTable != 0 || (*TBtCursor)(unsafe.Pointer(p)).Finfo.FnKey == iRow) {
|
|
(*TBtCursor)(unsafe.Pointer(p)).FeState = uint8(CURSOR_INVALID)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TBtCursor)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Invoke the profile callback. This routine is only called if we already
|
|
// ** know that the profile callback is defined and needs to be invoked.
|
|
// */
|
|
func _invokeProfileCallback(tls *libc.TLS, db uintptr, p uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var _ /* iElapse at bp+8 */ Tsqlite3_int64
|
|
var _ /* iNow at bp+0 */ Tsqlite3_int64
|
|
_sqlite3OsCurrentTimeInt64(tls, (*Tsqlite3)(unsafe.Pointer(db)).FpVfs, bp)
|
|
**(**Tsqlite3_int64)(__ccgo_up(bp + 8)) = (**(**Tsqlite3_int64)(__ccgo_up(bp)) - (*TVdbe)(unsafe.Pointer(p)).FstartTime) * int64(1000000)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FxProfile != 0 {
|
|
(*(*func(*libc.TLS, uintptr, uintptr, Tu64))(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3)(unsafe.Pointer(db)).FxProfile})))(tls, (*Tsqlite3)(unsafe.Pointer(db)).FpProfileArg, (*TVdbe)(unsafe.Pointer(p)).FzSql, libc.Uint64FromInt64(**(**Tsqlite3_int64)(__ccgo_up(bp + 8))))
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FmTrace)&int32(SQLITE_TRACE_PROFILE) != 0 {
|
|
(*(*func(*libc.TLS, Tu32, uintptr, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{*(*uintptr)(unsafe.Pointer(&(*Tsqlite3)(unsafe.Pointer(db)).Ftrace))})))(tls, uint32(SQLITE_TRACE_PROFILE), (*Tsqlite3)(unsafe.Pointer(db)).FpTraceArg, p, bp+8)
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FstartTime = 0
|
|
}
|
|
|
|
/*
|
|
** The checkProfileCallback(DB,P) macro checks to see if a profile callback
|
|
** is needed, and it invokes the callback if it is needed.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if pTerm is a virtual table LIMIT or OFFSET term.
|
|
// */
|
|
func _isLimitTerm(tls *libc.TLS, pTerm uintptr) (r int32) {
|
|
return libc.BoolInt32(libc.Int32FromUint8((*TWhereTerm)(unsafe.Pointer(pTerm)).FeMatchOp) >= int32(SQLITE_INDEX_CONSTRAINT_LIMIT) && libc.Int32FromUint8((*TWhereTerm)(unsafe.Pointer(pTerm)).FeMatchOp) <= int32(SQLITE_INDEX_CONSTRAINT_OFFSET))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the offset of the sector boundary at or immediately
|
|
// ** following the value in pPager->journalOff, assuming a sector
|
|
// ** size of pPager->sectorSize bytes.
|
|
// **
|
|
// ** i.e for a sector size of 512:
|
|
// **
|
|
// ** Pager.journalOff Return value
|
|
// ** ---------------------------------------
|
|
// ** 0 0
|
|
// ** 512 512
|
|
// ** 100 512
|
|
// ** 2000 2048
|
|
// **
|
|
// */
|
|
func _journalHdrOffset(tls *libc.TLS, pPager uintptr) (r Ti64) {
|
|
var c, offset Ti64
|
|
_, _ = c, offset
|
|
offset = 0
|
|
c = (*TPager)(unsafe.Pointer(pPager)).FjournalOff
|
|
if c != 0 {
|
|
offset = ((c-int64(1))/libc.Int64FromUint32((*TPager)(unsafe.Pointer(pPager)).FsectorSize) + int64(1)) * libc.Int64FromUint32((*TPager)(unsafe.Pointer(pPager)).FsectorSize)
|
|
}
|
|
return offset
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If pArg is a blob that seems like a JSONB blob, then initialize
|
|
// ** p to point to that JSONB and return TRUE. If pArg does not seem like
|
|
// ** a JSONB blob, then return FALSE.
|
|
// **
|
|
// ** For small BLOBs (having no more than 7 bytes of payload) a full
|
|
// ** validity check is done. So for small BLOBs this routine only returns
|
|
// ** true if the value is guaranteed to be a valid JSONB. For larger BLOBs
|
|
// ** (8 byte or more of payload) only the size of the outermost element is
|
|
// ** checked to verify that the BLOB is superficially valid JSONB.
|
|
// **
|
|
// ** A full JSONB validation is done on smaller BLOBs because those BLOBs might
|
|
// ** also be text JSON that has been incorrectly cast into a BLOB.
|
|
// ** (See tag-20240123-a and https://sqlite.org/forum/forumpost/012136abd5)
|
|
// ** If the BLOB is 9 bytes are larger, then it is not possible for the
|
|
// ** superficial size check done here to pass if the input is really text
|
|
// ** JSON so we do not need to look deeper in that case.
|
|
// **
|
|
// ** Why we only need to do full JSONB validation for smaller BLOBs:
|
|
// **
|
|
// ** The first byte of valid JSON text must be one of: '{', '[', '"', ' ', '\n',
|
|
// ** '\r', '\t', '-', or a digit '0' through '9'. Of these, only a subset
|
|
// ** can also be the first byte of JSONB: '{', '[', and digits '3'
|
|
// ** through '9'. In every one of those cases, the payload size is 7 bytes
|
|
// ** or less. So if we do full JSONB validation for every BLOB where the
|
|
// ** payload is less than 7 bytes, we will never get a false positive for
|
|
// ** JSONB on an input that is really text JSON.
|
|
// */
|
|
func _jsonArgIsJsonb(tls *libc.TLS, pArg uintptr, p uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var c, v1 Tu8
|
|
var n, v3 Tu32
|
|
var v2, v4 bool
|
|
var _ /* sz at bp+0 */ Tu32
|
|
_, _, _, _, _, _ = c, n, v1, v2, v3, v4
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
if Xsqlite3_value_type(tls, pArg) != int32(SQLITE_BLOB) {
|
|
return 0
|
|
}
|
|
(*TJsonParse)(unsafe.Pointer(p)).FaBlob = Xsqlite3_value_blob(tls, pArg)
|
|
(*TJsonParse)(unsafe.Pointer(p)).FnBlob = libc.Uint32FromInt32(Xsqlite3_value_bytes(tls, pArg))
|
|
if v2 = (*TJsonParse)(unsafe.Pointer(p)).FnBlob > uint32(0) && (*TJsonParse)(unsafe.Pointer(p)).FaBlob != uintptr(0); v2 {
|
|
v1 = **(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(p)).FaBlob))
|
|
c = v1
|
|
}
|
|
if v4 = v2 && libc.Int32FromUint8(v1)&int32(0x0f) <= int32(JSONB_OBJECT); v4 {
|
|
v3 = _jsonbPayloadSize(tls, p, uint32(0), bp)
|
|
n = v3
|
|
}
|
|
if v4 && v3 > uint32(0) && **(**Tu32)(__ccgo_up(bp))+n == (*TJsonParse)(unsafe.Pointer(p)).FnBlob && (libc.Int32FromUint8(c)&int32(0x0f) > int32(JSONB_FALSE) || **(**Tu32)(__ccgo_up(bp)) == uint32(0)) && (**(**Tu32)(__ccgo_up(bp)) > uint32(7) || libc.Int32FromUint8(c) != int32(0x7b) && libc.Int32FromUint8(c) != int32(0x5b) && !(libc.Int32FromUint8(_sqlite3CtypeMap[c])&libc.Int32FromInt32(0x04) != 0) || _jsonbValidityCheck(tls, p, uint32(0), (*TJsonParse)(unsafe.Pointer(p)).FnBlob, uint32(1)) == uint32(0)) {
|
|
return int32(1)
|
|
}
|
|
(*TJsonParse)(unsafe.Pointer(p)).FaBlob = uintptr(0)
|
|
(*TJsonParse)(unsafe.Pointer(p)).FnBlob = uint32(0)
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* The query strategy is to look for an equality constraint on the json
|
|
// ** column. Without such a constraint, the table cannot operate. idxNum is
|
|
// ** 1 if the constraint is found, 3 if the constraint and zRoot are found,
|
|
// ** and 0 otherwise.
|
|
// */
|
|
func _jsonEachBestIndex(tls *libc.TLS, tab uintptr, pIdxInfo uintptr) (r int32) {
|
|
var aIdx [2]int32
|
|
var i, iCol, iMask, idxMask, unusableMask, v1 int32
|
|
var pConstraint uintptr
|
|
_, _, _, _, _, _, _, _ = aIdx, i, iCol, iMask, idxMask, pConstraint, unusableMask, v1 /* Index of constraints for JSON and ROOT */
|
|
unusableMask = 0 /* Mask of unusable JSON and ROOT constraints */
|
|
idxMask = 0
|
|
/* This implementation assumes that JSON and ROOT are the last two
|
|
** columns in the table */
|
|
_ = tab
|
|
v1 = -libc.Int32FromInt32(1)
|
|
aIdx[int32(1)] = v1
|
|
aIdx[0] = v1
|
|
pConstraint = (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraint
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FnConstraint) {
|
|
break
|
|
}
|
|
if (*Tsqlite3_index_constraint)(unsafe.Pointer(pConstraint)).FiColumn < int32(JEACH_JSON) {
|
|
goto _2
|
|
}
|
|
iCol = (*Tsqlite3_index_constraint)(unsafe.Pointer(pConstraint)).FiColumn - int32(JEACH_JSON)
|
|
iMask = int32(1) << iCol
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(pConstraint)).Fusable) == 0 {
|
|
unusableMask = unusableMask | iMask
|
|
} else {
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(pConstraint)).Fop) == int32(SQLITE_INDEX_CONSTRAINT_EQ) {
|
|
aIdx[iCol] = i
|
|
idxMask = idxMask | iMask
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
pConstraint += 12
|
|
}
|
|
if (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FnOrderBy > 0 && (**(**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)).ForderByConsumed = int32(1)
|
|
}
|
|
if unusableMask & ^idxMask != 0 {
|
|
/* If there are any unusable constraints on JSON or ROOT, then reject
|
|
** this entire plan */
|
|
return int32(SQLITE_CONSTRAINT)
|
|
}
|
|
if aIdx[0] < 0 {
|
|
/* No JSON input. Leave estimatedCost at the huge value that it was
|
|
** initialized to to discourage the query planner from selecting this
|
|
** plan. */
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FidxNum = 0
|
|
} else {
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedCost = float64(1)
|
|
i = aIdx[0]
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(i)*8))).FargvIndex = int32(1)
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(i)*8))).Fomit = uint8(1)
|
|
if aIdx[int32(1)] < 0 {
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FidxNum = int32(1) /* Only JSON supplied. Plan 1 */
|
|
} else {
|
|
i = aIdx[int32(1)]
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(i)*8))).FargvIndex = int32(2)
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(i)*8))).Fomit = uint8(1)
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FidxNum = int32(3) /* Both JSON and ROOT are supplied. Plan 3 */
|
|
}
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Return the current rowid value */
|
|
func _jsonEachRowid(tls *libc.TLS, cur uintptr, pRowid uintptr) (r int32) {
|
|
var p uintptr
|
|
_ = p
|
|
p = cur
|
|
**(**Tsqlite_int64)(__ccgo_up(pRowid)) = libc.Int64FromUint32((*TJsonEachCursor)(unsafe.Pointer(p)).FiRowid)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Translate a single byte of Hex into an integer.
|
|
// ** This routine only gives a correct answer if h really is a valid hexadecimal
|
|
// ** character: 0..9a..fA..F. But unlike sqlite3HexToInt(), it does not
|
|
// ** assert() if the digit is not hex.
|
|
// */
|
|
func _jsonHexToInt(tls *libc.TLS, h int32) (r Tu8) {
|
|
h = h + int32(9)*(int32(1)&(h>>int32(6)))
|
|
return libc.Uint8FromInt32(h & libc.Int32FromInt32(0xf))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Remove a single character from the end of the string
|
|
// */
|
|
func _jsonStringTrimOneChar(tls *libc.TLS, p uintptr) {
|
|
if libc.Int32FromUint8((*TJsonString)(unsafe.Pointer(p)).FeErr) == 0 {
|
|
(*TJsonString)(unsafe.Pointer(p)).FnUsed = (*TJsonString)(unsafe.Pointer(p)).FnUsed - 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* The byte at index i is a node type-code. This routine
|
|
// ** determines the payload size for that node and writes that
|
|
// ** payload size in to *pSz. It returns the offset from i to the
|
|
// ** beginning of the payload. Return 0 on error.
|
|
// */
|
|
func _jsonbPayloadSize(tls *libc.TLS, pParse uintptr, i Tu32, pSz uintptr) (r Tu32) {
|
|
var n, sz Tu32
|
|
var x, v1 Tu8
|
|
_, _, _, _ = n, sz, x, v1
|
|
if i >= (*TJsonParse)(unsafe.Pointer(pParse)).FnBlob {
|
|
**(**Tu32)(__ccgo_up(pSz)) = uint32(0)
|
|
return uint32(0)
|
|
} else {
|
|
v1 = libc.Uint8FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i)))) >> libc.Int32FromInt32(4))
|
|
x = v1
|
|
if libc.Int32FromUint8(v1) <= int32(11) {
|
|
sz = uint32(x)
|
|
n = uint32(1)
|
|
} else {
|
|
if libc.Int32FromUint8(x) == int32(12) {
|
|
if i+uint32(1) >= (*TJsonParse)(unsafe.Pointer(pParse)).FnBlob {
|
|
**(**Tu32)(__ccgo_up(pSz)) = uint32(0)
|
|
return uint32(0)
|
|
}
|
|
sz = uint32(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(1)))))
|
|
n = uint32(2)
|
|
} else {
|
|
if libc.Int32FromUint8(x) == int32(13) {
|
|
if i+uint32(2) >= (*TJsonParse)(unsafe.Pointer(pParse)).FnBlob {
|
|
**(**Tu32)(__ccgo_up(pSz)) = uint32(0)
|
|
return uint32(0)
|
|
}
|
|
sz = libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(1)))))<<int32(8) + libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(2))))))
|
|
n = uint32(3)
|
|
} else {
|
|
if libc.Int32FromUint8(x) == int32(14) {
|
|
if i+uint32(4) >= (*TJsonParse)(unsafe.Pointer(pParse)).FnBlob {
|
|
**(**Tu32)(__ccgo_up(pSz)) = uint32(0)
|
|
return uint32(0)
|
|
}
|
|
sz = uint32(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(1)))))<<libc.Int32FromInt32(24) + libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(2)))))<<libc.Int32FromInt32(16)) + libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(3)))))<<libc.Int32FromInt32(8)) + uint32(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(4)))))
|
|
n = uint32(5)
|
|
} else {
|
|
if i+uint32(8) >= (*TJsonParse)(unsafe.Pointer(pParse)).FnBlob || libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(1))))) != 0 || libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(2))))) != 0 || libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(3))))) != 0 || libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(4))))) != 0 {
|
|
**(**Tu32)(__ccgo_up(pSz)) = uint32(0)
|
|
return uint32(0)
|
|
}
|
|
sz = uint32(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(5)))))<<libc.Int32FromInt32(24) + libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(6)))))<<libc.Int32FromInt32(16)) + libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(7)))))<<libc.Int32FromInt32(8)) + uint32(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(i+uint32(8)))))
|
|
n = uint32(9)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if libc.Int64FromUint32(i)+libc.Int64FromUint32(sz)+libc.Int64FromUint32(n) > libc.Int64FromUint32((*TJsonParse)(unsafe.Pointer(pParse)).FnBlob) && libc.Int64FromUint32(i)+libc.Int64FromUint32(sz)+libc.Int64FromUint32(n) > libc.Int64FromUint32((*TJsonParse)(unsafe.Pointer(pParse)).FnBlob-libc.Uint32FromInt32((*TJsonParse)(unsafe.Pointer(pParse)).Fdelta)) {
|
|
**(**Tu32)(__ccgo_up(pSz)) = uint32(0)
|
|
return uint32(0)
|
|
}
|
|
**(**Tu32)(__ccgo_up(pSz)) = sz
|
|
return n
|
|
}
|
|
|
|
func _lookasideMallocSize(tls *libc.TLS, db uintptr, p uintptr) (r int32) {
|
|
var v1 int32
|
|
_ = v1
|
|
if p < (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpMiddle {
|
|
v1 = libc.Int32FromUint16((*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FszTrue)
|
|
} else {
|
|
v1 = int32(LOOKASIDE_SMALL)
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Try to enlarge the memory allocation to hold at least sz bytes
|
|
// */
|
|
func _memdbEnlarge(tls *libc.TLS, p uintptr, newSz Tsqlite3_int64) (r int32) {
|
|
var pNew uintptr
|
|
_ = pNew
|
|
if (*TMemStore)(unsafe.Pointer(p)).FmFlags&uint32(SQLITE_DESERIALIZE_RESIZEABLE) == uint32(0) || (*TMemStore)(unsafe.Pointer(p)).FnMmap > 0 {
|
|
return int32(SQLITE_FULL)
|
|
}
|
|
if newSz > (*TMemStore)(unsafe.Pointer(p)).FszMax {
|
|
return int32(SQLITE_FULL)
|
|
}
|
|
newSz = newSz * int64(2)
|
|
if newSz > (*TMemStore)(unsafe.Pointer(p)).FszMax {
|
|
newSz = (*TMemStore)(unsafe.Pointer(p)).FszMax
|
|
}
|
|
pNew = _sqlite3Realloc(tls, (*TMemStore)(unsafe.Pointer(p)).FaData, libc.Uint64FromInt64(newSz))
|
|
if pNew == uintptr(0) {
|
|
return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(12)<<libc.Int32FromInt32(8)
|
|
}
|
|
(*TMemStore)(unsafe.Pointer(p)).FaData = pNew
|
|
(*TMemStore)(unsafe.Pointer(p)).FszAlloc = newSz
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move the cursor down to the right-most leaf entry beneath the
|
|
// ** page to which it is currently pointing. Notice the difference
|
|
// ** between moveToLeftmost() and moveToRightmost(). moveToLeftmost()
|
|
// ** finds the left-most entry beneath the *entry* whereas moveToRightmost()
|
|
// ** finds the right-most entry beneath the *page*.
|
|
// **
|
|
// ** The right-most entry is the one with the largest key - the last
|
|
// ** key in ascending order.
|
|
// */
|
|
func _moveToRightmost(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
var pPage, v1 uintptr
|
|
var pgno TPgno
|
|
var rc int32
|
|
_, _, _, _ = pPage, pgno, rc, v1
|
|
rc = SQLITE_OK
|
|
pPage = uintptr(0)
|
|
for {
|
|
v1 = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
pPage = v1
|
|
if !!((*TMemPage)(unsafe.Pointer(v1)).Fleaf != 0) {
|
|
break
|
|
}
|
|
pgno = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pPage)).FaData+uintptr(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset)+int32(8)))
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = (*TMemPage)(unsafe.Pointer(pPage)).FnCell
|
|
rc = _moveToChild(tls, pCur, pgno)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
}
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = libc.Uint16FromInt32(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) - int32(1))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Deserialize cell iCell of node pNode. Populate the structure pointed
|
|
// ** to by pCell with the results.
|
|
// */
|
|
func _nodeGetCell(tls *libc.TLS, pRtree uintptr, pNode uintptr, iCell int32, pCell uintptr) {
|
|
var ii int32
|
|
var pCoord, pData uintptr
|
|
_, _, _ = ii, pCoord, pData
|
|
ii = 0
|
|
(*TRtreeCell)(unsafe.Pointer(pCell)).FiRowid = _nodeGetRowid(tls, pRtree, pNode, iCell)
|
|
pData = (*TRtreeNode)(unsafe.Pointer(pNode)).FzData + uintptr(libc.Int32FromInt32(12)+libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnBytesPerCell)*iCell)
|
|
pCoord = pCell + 8
|
|
for cond := true; cond; cond = ii < libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2) {
|
|
_readCoord(tls, pData, pCoord+uintptr(ii)*4)
|
|
_readCoord(tls, pData+uintptr(4), pCoord+uintptr(ii+int32(1))*4)
|
|
pData = pData + uintptr(8)
|
|
ii = ii + int32(2)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return coordinate iCoord from cell iCell in node pNode.
|
|
// */
|
|
func _nodeGetCoord(tls *libc.TLS, pRtree uintptr, pNode uintptr, iCell int32, iCoord int32, pCoord uintptr) {
|
|
_readCoord(tls, (*TRtreeNode)(unsafe.Pointer(pNode)).FzData+uintptr(int32(12)+libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnBytesPerCell)*iCell+int32(4)*iCoord), pCoord)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the 64-bit integer value associated with cell iCell of
|
|
// ** node pNode. If pNode is a leaf node, this is a rowid. If it is
|
|
// ** an internal node, then the 64-bit integer is a child page number.
|
|
// */
|
|
func _nodeGetRowid(tls *libc.TLS, pRtree uintptr, pNode uintptr, iCell int32) (r Ti64) {
|
|
return _readInt64(tls, (*TRtreeNode)(unsafe.Pointer(pNode)).FzData+uintptr(int32(4)+libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnBytesPerCell)*iCell))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Given a node number iNode, return the corresponding key to use
|
|
// ** in the Rtree.aHash table.
|
|
// */
|
|
func _nodeHash(tls *libc.TLS, iNode Ti64) (r uint32) {
|
|
return libc.Uint32FromInt64(iNode) % uint32(HASHSIZE)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Insert the contents of cell pCell into node pNode. If the insert
|
|
// ** is successful, return SQLITE_OK.
|
|
// **
|
|
// ** If there is not enough free space in pNode, return SQLITE_FULL.
|
|
// */
|
|
func _nodeInsertCell(tls *libc.TLS, pRtree uintptr, pNode uintptr, pCell uintptr) (r int32) {
|
|
var nCell, nMaxCell int32
|
|
_, _ = nCell, nMaxCell /* Maximum number of cells for pNode */
|
|
nMaxCell = ((*TRtree)(unsafe.Pointer(pRtree)).FiNodeSize - int32(4)) / libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnBytesPerCell)
|
|
nCell = _readInt16(tls, (*TRtreeNode)(unsafe.Pointer(pNode)).FzData+2)
|
|
if nCell < nMaxCell {
|
|
_nodeOverwriteCell(tls, pRtree, pNode, pCell, nCell)
|
|
_writeInt16(tls, (*TRtreeNode)(unsafe.Pointer(pNode)).FzData+2, nCell+int32(1))
|
|
(*TRtreeNode)(unsafe.Pointer(pNode)).FisDirty = int32(1)
|
|
}
|
|
return libc.BoolInt32(nCell == nMaxCell)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Overwrite cell iCell of node pNode with the contents of pCell.
|
|
// */
|
|
func _nodeOverwriteCell(tls *libc.TLS, pRtree uintptr, pNode uintptr, pCell uintptr, iCell int32) {
|
|
var ii int32
|
|
var p uintptr
|
|
_, _ = ii, p
|
|
p = (*TRtreeNode)(unsafe.Pointer(pNode)).FzData + uintptr(int32(4)+libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnBytesPerCell)*iCell)
|
|
p = p + uintptr(_writeInt64(tls, p, (*TRtreeCell)(unsafe.Pointer(pCell)).FiRowid))
|
|
ii = 0
|
|
for {
|
|
if !(ii < libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2)) {
|
|
break
|
|
}
|
|
p = p + uintptr(_writeCoord(tls, p, pCell+8+uintptr(ii)*4))
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
(*TRtreeNode)(unsafe.Pointer(pNode)).FisDirty = int32(1)
|
|
}
|
|
|
|
func _nolockCheckReservedLock(tls *libc.TLS, NotUsed uintptr, pResOut uintptr) (r int32) {
|
|
_ = NotUsed
|
|
**(**int32)(__ccgo_up(pResOut)) = 0
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close the file.
|
|
// */
|
|
func _nolockClose(tls *libc.TLS, id uintptr) (r int32) {
|
|
return _closeUnixFile(tls, id)
|
|
}
|
|
|
|
/******************* End of the no-op lock implementation *********************
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
************************* Begin dot-file Locking ******************************
|
|
**
|
|
** The dotfile locking implementation uses the existence of separate lock
|
|
** files (really a directory) to control access to the database. This works
|
|
** on just about every filesystem imaginable. But there are serious downsides:
|
|
**
|
|
** (1) There is zero concurrency. A single reader blocks all other
|
|
** connections from reading or writing the database.
|
|
**
|
|
** (2) An application crash or power loss can leave stale lock files
|
|
** sitting around that need to be cleared manually.
|
|
**
|
|
** Nevertheless, a dotlock is an appropriate locking mode for use if no
|
|
** other locking strategy is available.
|
|
**
|
|
** Dotfile locking works by creating a subdirectory in the same directory as
|
|
** the database and with the same name but with a ".lock" extension added.
|
|
** The existence of a lock directory implies an EXCLUSIVE lock. All other
|
|
** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
|
|
*/
|
|
|
|
/*
|
|
** The file suffix added to the data base filename in order to create the
|
|
** lock directory.
|
|
*/
|
|
|
|
var _nolockIoFinder = uintptr(0)
|
|
|
|
func _nolockIoFinderImpl(tls *libc.TLS, z uintptr, p uintptr) (r uintptr) {
|
|
_ = z
|
|
_ = p
|
|
return uintptr(unsafe.Pointer(&_nolockIoMethods))
|
|
}
|
|
|
|
var _nolockIoMethods = Tsqlite3_io_methods{
|
|
FiVersion: int32(3),
|
|
}
|
|
|
|
func _nolockLock(tls *libc.TLS, NotUsed uintptr, NotUsed2 int32) (r int32) {
|
|
_ = NotUsed
|
|
_ = NotUsed2
|
|
return SQLITE_OK
|
|
}
|
|
|
|
func _nolockUnlock(tls *libc.TLS, NotUsed uintptr, NotUsed2 int32) (r int32) {
|
|
_ = NotUsed
|
|
_ = NotUsed2
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
|
|
// ** none.
|
|
// **
|
|
// ** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
|
|
// ** But it does set pMem->u.r and pMem->u.i appropriately.
|
|
// */
|
|
func _numericType(tls *libc.TLS, pMem uintptr) (r Tu16) {
|
|
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 {
|
|
return libc.Uint16FromInt32(libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags) & (libc.Int32FromInt32(MEM_Int) | libc.Int32FromInt32(MEM_Real) | libc.Int32FromInt32(MEM_IntReal) | libc.Int32FromInt32(MEM_Null)))
|
|
}
|
|
return _computeNumericType(tls, pMem)
|
|
return uint16(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Ensure that the sub-journal file is open. If it is already open, this
|
|
// ** function is a no-op.
|
|
// **
|
|
// ** SQLITE_OK is returned if everything goes according to plan. An
|
|
// ** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
|
|
// ** fails.
|
|
// */
|
|
func _openSubJournal(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
var flags, nStmtSpill, rc int32
|
|
_, _, _ = flags, nStmtSpill, rc
|
|
rc = SQLITE_OK
|
|
if !((*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fsjfd)).FpMethods != libc.UintptrFromInt32(0)) {
|
|
flags = libc.Int32FromInt32(SQLITE_OPEN_SUBJOURNAL) | libc.Int32FromInt32(SQLITE_OPEN_READWRITE) | libc.Int32FromInt32(SQLITE_OPEN_CREATE) | libc.Int32FromInt32(SQLITE_OPEN_EXCLUSIVE) | libc.Int32FromInt32(SQLITE_OPEN_DELETEONCLOSE)
|
|
nStmtSpill = _sqlite3Config.FnStmtSpill
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) == int32(PAGER_JOURNALMODE_MEMORY) || (*TPager)(unsafe.Pointer(pPager)).FsubjInMemory != 0 {
|
|
nStmtSpill = -int32(1)
|
|
}
|
|
rc = _sqlite3JournalOpen(tls, (*TPager)(unsafe.Pointer(pPager)).FpVfs, uintptr(0), (*TPager)(unsafe.Pointer(pPager)).Fsjfd, flags, nStmtSpill)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Translate from TK_xx operator to WO_xx bitmask.
|
|
// */
|
|
func _operatorMask(tls *libc.TLS, op int32) (r Tu16) {
|
|
var c Tu16
|
|
_ = c
|
|
if op >= int32(TK_EQ) {
|
|
c = libc.Uint16FromInt32(libc.Int32FromInt32(WO_EQ) << (op - libc.Int32FromInt32(TK_EQ)))
|
|
} else {
|
|
if op == int32(TK_IN) {
|
|
c = uint16(WO_IN)
|
|
} else {
|
|
if op == int32(TK_ISNULL) {
|
|
c = uint16(WO_ISNULL)
|
|
} else {
|
|
c = uint16(WO_IS)
|
|
}
|
|
}
|
|
}
|
|
return c
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The following routine implements the rough equivalent of localtime_r()
|
|
// ** using whatever operating-system specific localtime facility that
|
|
// ** is available. This routine returns 0 on success and
|
|
// ** non-zero on any kind of error.
|
|
// **
|
|
// ** If the sqlite3GlobalConfig.bLocaltimeFault variable is non-zero then this
|
|
// ** routine will always fail. If bLocaltimeFault is nonzero and
|
|
// ** sqlite3GlobalConfig.xAltLocaltime is not NULL, then xAltLocaltime() is
|
|
// ** invoked in place of the OS-defined localtime() function.
|
|
// **
|
|
// ** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C
|
|
// ** library function localtime_r() is used to assist in the calculation of
|
|
// ** local time.
|
|
// */
|
|
func _osLocaltime(tls *libc.TLS, t uintptr, pTm uintptr) (r int32) {
|
|
var mutex, pX uintptr
|
|
var rc int32
|
|
_, _, _ = mutex, pX, rc
|
|
mutex = _sqlite3MutexAlloc(tls, int32(SQLITE_MUTEX_STATIC_MAIN))
|
|
Xsqlite3_mutex_enter(tls, mutex)
|
|
pX = libc.Xlocaltime(tls, t)
|
|
if _sqlite3Config.FbLocaltimeFault != 0 {
|
|
if _sqlite3Config.FxAltLocaltime != uintptr(0) && 0 == (*(*func(*libc.TLS, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.FxAltLocaltime})))(tls, t, pTm) {
|
|
pX = pTm
|
|
} else {
|
|
pX = uintptr(0)
|
|
}
|
|
}
|
|
if pX != 0 {
|
|
**(**Ttm)(__ccgo_up(pTm)) = **(**Ttm)(__ccgo_up(pX))
|
|
}
|
|
Xsqlite3_mutex_leave(tls, mutex)
|
|
rc = libc.BoolInt32(pX == uintptr(0))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Attempt to take an exclusive lock on the database file. If a PENDING lock
|
|
// ** is obtained instead, immediately release it.
|
|
// */
|
|
func _pagerExclusiveLock(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
var eOrigLock Tu8
|
|
var rc int32
|
|
_, _ = eOrigLock, rc /* Original lock */
|
|
eOrigLock = (*TPager)(unsafe.Pointer(pPager)).FeLock
|
|
rc = _pagerLockDb(tls, pPager, int32(EXCLUSIVE_LOCK))
|
|
if rc != SQLITE_OK {
|
|
/* If the attempt to grab the exclusive lock failed, release the
|
|
** pending lock that may have been obtained instead. */
|
|
_pagerUnlockDb(tls, pPager, libc.Int32FromUint8(eOrigLock))
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The write transaction open on pPager is being committed (bCommit==1)
|
|
// ** or rolled back (bCommit==0).
|
|
// **
|
|
// ** Return TRUE if and only if all dirty pages should be flushed to disk.
|
|
// **
|
|
// ** Rules:
|
|
// **
|
|
// ** * For non-TEMP databases, always sync to disk. This is necessary
|
|
// ** for transactions to be durable.
|
|
// **
|
|
// ** * Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing
|
|
// ** file has been created already (via a spill on pagerStress()) and
|
|
// ** when the number of dirty pages in memory exceeds 25% of the total
|
|
// ** cache size.
|
|
// */
|
|
func _pagerFlushOnCommit(tls *libc.TLS, pPager uintptr, bCommit int32) (r int32) {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FtempFile) == 0 {
|
|
return int32(1)
|
|
}
|
|
if !(bCommit != 0) {
|
|
return 0
|
|
}
|
|
if !((*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Ffd)).FpMethods != libc.UintptrFromInt32(0)) {
|
|
return 0
|
|
}
|
|
return libc.BoolInt32(_sqlite3PCachePercentDirty(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache) >= int32(25))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Lock the database file to level eLock, which must be either SHARED_LOCK,
|
|
// ** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
|
|
// ** Pager.eLock variable to the new locking state.
|
|
// **
|
|
// ** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
|
|
// ** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
|
|
// ** See the comment above the #define of UNKNOWN_LOCK for an explanation
|
|
// ** of this.
|
|
// */
|
|
func _pagerLockDb(tls *libc.TLS, pPager uintptr, eLock int32) (r int32) {
|
|
var rc, v1 int32
|
|
_, _ = rc, v1
|
|
rc = SQLITE_OK
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeLock) < eLock || libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeLock) == libc.Int32FromInt32(EXCLUSIVE_LOCK)+libc.Int32FromInt32(1) {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FnoLock != 0 {
|
|
v1 = SQLITE_OK
|
|
} else {
|
|
v1 = _sqlite3OsLock(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, eLock)
|
|
}
|
|
rc = v1
|
|
if rc == SQLITE_OK && (libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeLock) != libc.Int32FromInt32(EXCLUSIVE_LOCK)+libc.Int32FromInt32(1) || eLock == int32(EXCLUSIVE_LOCK)) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FeLock = libc.Uint8FromInt32(eLock)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check if the *-wal file that corresponds to the database opened by pPager
|
|
// ** exists if the database is not empty, or verify that the *-wal file does
|
|
// ** not exist (by deleting it) if the database file is empty.
|
|
// **
|
|
// ** If the database is not empty and the *-wal file exists, open the pager
|
|
// ** in WAL mode. If the database is empty or if no *-wal file exists and
|
|
// ** if no error occurs, make sure Pager.journalMode is not set to
|
|
// ** PAGER_JOURNALMODE_WAL.
|
|
// **
|
|
// ** Return SQLITE_OK or an error code.
|
|
// **
|
|
// ** The caller must hold a SHARED lock on the database file to call this
|
|
// ** function. Because an EXCLUSIVE lock on the db file is required to delete
|
|
// ** a WAL on a none-empty database, this ensures there is no race condition
|
|
// ** between the xAccess() below and an xDelete() being executed by some
|
|
// ** other connection.
|
|
// */
|
|
func _pagerOpenWalIfPresent(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc int32
|
|
var _ /* isWal at bp+0 */ int32
|
|
var _ /* nPage at bp+4 */ TPgno
|
|
_ = rc
|
|
rc = SQLITE_OK
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FtempFile != 0) { /* True if WAL file exists */
|
|
rc = _sqlite3OsAccess(tls, (*TPager)(unsafe.Pointer(pPager)).FpVfs, (*TPager)(unsafe.Pointer(pPager)).FzWal, SQLITE_ACCESS_EXISTS, bp)
|
|
if rc == SQLITE_OK {
|
|
if **(**int32)(__ccgo_up(bp)) != 0 { /* Size of the database file */
|
|
rc = _pagerPagecount(tls, pPager, bp+4)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
if **(**TPgno)(__ccgo_up(bp + 4)) == uint32(0) {
|
|
rc = _sqlite3OsDelete(tls, (*TPager)(unsafe.Pointer(pPager)).FpVfs, (*TPager)(unsafe.Pointer(pPager)).FzWal, 0)
|
|
} else {
|
|
rc = _sqlite3PagerOpenWal(tls, pPager, uintptr(0))
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) == int32(PAGER_JOURNALMODE_WAL) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalMode = uint8(PAGER_JOURNALMODE_DELETE)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called as part of the transition from PAGER_OPEN
|
|
// ** to PAGER_READER state to determine the size of the database file
|
|
// ** in pages (assuming the page size currently stored in Pager.pageSize).
|
|
// **
|
|
// ** If no error occurs, SQLITE_OK is returned and the size of the database
|
|
// ** in pages is stored in *pnPage. Otherwise, an error code (perhaps
|
|
// ** SQLITE_IOERR_FSTAT) is returned and *pnPage is left unmodified.
|
|
// */
|
|
func _pagerPagecount(tls *libc.TLS, pPager uintptr, pnPage uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var nPage TPgno
|
|
var rc int32
|
|
var _ /* n at bp+0 */ Ti64
|
|
_, _ = nPage, rc /* Value to return via *pnPage */
|
|
/* Query the WAL sub-system for the database size. The WalDbsize()
|
|
** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or
|
|
** if the database size is not available. The database size is not
|
|
** available from the WAL sub-system if the log file is empty or
|
|
** contains no valid committed transactions.
|
|
*/
|
|
nPage = _sqlite3WalDbsize(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal)
|
|
/* If the number of pages in the database is not available from the
|
|
** WAL sub-system, determine the page count based on the size of
|
|
** the database file. If the size of the database file is not an
|
|
** integer multiple of the page-size, round up the result.
|
|
*/
|
|
if nPage == uint32(0) && (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Ffd)).FpMethods != uintptr(0) {
|
|
**(**Ti64)(__ccgo_up(bp)) = 0 /* Size of db file in bytes */
|
|
rc = _sqlite3OsFileSize(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, bp)
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
nPage = libc.Uint32FromInt64((**(**Ti64)(__ccgo_up(bp)) + (*TPager)(unsafe.Pointer(pPager)).FpageSize - libc.Int64FromInt32(1)) / (*TPager)(unsafe.Pointer(pPager)).FpageSize)
|
|
}
|
|
/* If the current number of pages in the file is greater than the
|
|
** configured maximum pager number, increase the allowed limit so
|
|
** that the file can be read.
|
|
*/
|
|
if nPage > (*TPager)(unsafe.Pointer(pPager)).FmxPgno {
|
|
(*TPager)(unsafe.Pointer(pPager)).FmxPgno = nPage
|
|
}
|
|
**(**TPgno)(__ccgo_up(pnPage)) = nPage
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Release a reference to page pPg. pPg must have been returned by an
|
|
// ** earlier call to pagerAcquireMapPage().
|
|
// */
|
|
func _pagerReleaseMapPage(tls *libc.TLS, pPg uintptr) {
|
|
var pPager uintptr
|
|
_ = pPager
|
|
pPager = (*TPgHdr)(unsafe.Pointer(pPg)).FpPager
|
|
(*TPager)(unsafe.Pointer(pPager)).FnMmapOut = (*TPager)(unsafe.Pointer(pPager)).FnMmapOut - 1
|
|
(*TPgHdr)(unsafe.Pointer(pPg)).FpDirty = (*TPager)(unsafe.Pointer(pPager)).FpMmapFreelist
|
|
(*TPager)(unsafe.Pointer(pPager)).FpMmapFreelist = pPg
|
|
_sqlite3OsUnfetch(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, libc.Int64FromUint32((*TPgHdr)(unsafe.Pointer(pPg)).Fpgno-libc.Uint32FromInt32(1))*(*TPager)(unsafe.Pointer(pPager)).FpageSize, (*TPgHdr)(unsafe.Pointer(pPg)).FpData)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Execute a rollback if a transaction is active and unlock the
|
|
// ** database file.
|
|
// **
|
|
// ** If the pager has already entered the ERROR state, do not attempt
|
|
// ** the rollback at this time. Instead, pager_unlock() is called. The
|
|
// ** call to pager_unlock() will discard all in-memory pages, unlock
|
|
// ** the database file and move the pager back to OPEN state. If this
|
|
// ** means that there is a hot-journal left in the file-system, the next
|
|
// ** connection to obtain a shared lock on the pager (which may be this one)
|
|
// ** will roll it back.
|
|
// **
|
|
// ** If the pager has not already entered the ERROR state, but an IO or
|
|
// ** malloc error occurs during a rollback, then this will itself cause
|
|
// ** the pager to enter the ERROR state. Which will be cleared by the
|
|
// ** call to pager_unlock(), as described above.
|
|
// */
|
|
func _pagerUnlockAndRollback(tls *libc.TLS, pPager uintptr) {
|
|
var eLock Tu8
|
|
var errCode int32
|
|
_, _ = eLock, errCode
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) != int32(PAGER_ERROR) && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) != PAGER_OPEN {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) >= int32(PAGER_WRITER_LOCKED) {
|
|
_sqlite3BeginBenignMalloc(tls)
|
|
_sqlite3PagerRollback(tls, pPager)
|
|
_sqlite3EndBenignMalloc(tls)
|
|
} else {
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0) {
|
|
_pager_end_transaction(tls, pPager, 0, 0)
|
|
}
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_ERROR) && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) == int32(PAGER_JOURNALMODE_MEMORY) && (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != uintptr(0) {
|
|
/* Special case for a ROLLBACK due to I/O error with an in-memory
|
|
** journal: We have to rollback immediately, before the journal is
|
|
** closed, because once it is closed, all content is forgotten. */
|
|
errCode = (*TPager)(unsafe.Pointer(pPager)).FerrCode
|
|
eLock = (*TPager)(unsafe.Pointer(pPager)).FeLock
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_OPEN)
|
|
(*TPager)(unsafe.Pointer(pPager)).FerrCode = SQLITE_OK
|
|
(*TPager)(unsafe.Pointer(pPager)).FeLock = uint8(EXCLUSIVE_LOCK)
|
|
_pager_playback(tls, pPager, int32(1))
|
|
(*TPager)(unsafe.Pointer(pPager)).FerrCode = errCode
|
|
(*TPager)(unsafe.Pointer(pPager)).FeLock = eLock
|
|
}
|
|
}
|
|
_pager_unlock(tls, pPager)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Unlock the database file to level eLock, which must be either NO_LOCK
|
|
// ** or SHARED_LOCK. Regardless of whether or not the call to xUnlock()
|
|
// ** succeeds, set the Pager.eLock variable to match the (attempted) new lock.
|
|
// **
|
|
// ** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
|
|
// ** called, do not modify it. See the comment above the #define of
|
|
// ** UNKNOWN_LOCK for an explanation of this.
|
|
// */
|
|
func _pagerUnlockDb(tls *libc.TLS, pPager uintptr, eLock int32) (r int32) {
|
|
var rc, v1 int32
|
|
_, _ = rc, v1
|
|
rc = SQLITE_OK
|
|
if (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Ffd)).FpMethods != uintptr(0) {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FnoLock != 0 {
|
|
v1 = SQLITE_OK
|
|
} else {
|
|
v1 = _sqlite3OsUnlock(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, eLock)
|
|
}
|
|
rc = v1
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeLock) != libc.Int32FromInt32(EXCLUSIVE_LOCK)+libc.Int32FromInt32(1) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FeLock = libc.Uint8FromInt32(eLock)
|
|
}
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FchangeCountDone = (*TPager)(unsafe.Pointer(pPager)).FtempFile /* ticket fb3b3024ea238d5c */
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine ends a transaction. A transaction is usually ended by
|
|
// ** either a COMMIT or a ROLLBACK operation. This routine may be called
|
|
// ** after rollback of a hot-journal, or if an error occurs while opening
|
|
// ** the journal file or writing the very first journal-header of a
|
|
// ** database transaction.
|
|
// **
|
|
// ** This routine is never called in PAGER_ERROR state. If it is called
|
|
// ** in PAGER_NONE or PAGER_SHARED state and the lock held is less
|
|
// ** exclusive than a RESERVED lock, it is a no-op.
|
|
// **
|
|
// ** Otherwise, any active savepoints are released.
|
|
// **
|
|
// ** If the journal file is open, then it is "finalized". Once a journal
|
|
// ** file has been finalized it is not possible to use it to roll back a
|
|
// ** transaction. Nor will it be considered to be a hot-journal by this
|
|
// ** or any other database connection. Exactly how a journal is finalized
|
|
// ** depends on whether or not the pager is running in exclusive mode and
|
|
// ** the current journal-mode (Pager.journalMode value), as follows:
|
|
// **
|
|
// ** journalMode==MEMORY
|
|
// ** Journal file descriptor is simply closed. This destroys an
|
|
// ** in-memory journal.
|
|
// **
|
|
// ** journalMode==TRUNCATE
|
|
// ** Journal file is truncated to zero bytes in size.
|
|
// **
|
|
// ** journalMode==PERSIST
|
|
// ** The first 28 bytes of the journal file are zeroed. This invalidates
|
|
// ** the first journal header in the file, and hence the entire journal
|
|
// ** file. An invalid journal file cannot be rolled back.
|
|
// **
|
|
// ** journalMode==DELETE
|
|
// ** The journal file is closed and deleted using sqlite3OsDelete().
|
|
// **
|
|
// ** If the pager is running in exclusive mode, this method of finalizing
|
|
// ** the journal file is never used. Instead, if the journalMode is
|
|
// ** DELETE and the pager is in exclusive mode, the method described under
|
|
// ** journalMode==PERSIST is used instead.
|
|
// **
|
|
// ** After the journal is finalized, the pager moves to PAGER_READER state.
|
|
// ** If running in non-exclusive rollback mode, the lock on the file is
|
|
// ** downgraded to a SHARED_LOCK.
|
|
// **
|
|
// ** SQLITE_OK is returned if no error occurs. If an error occurs during
|
|
// ** any of the IO operations to finalize the journal file or unlock the
|
|
// ** database then the IO error code is returned to the user. If the
|
|
// ** operation to finalize the journal file fails, then the code still
|
|
// ** tries to unlock the database file if not in exclusive mode. If the
|
|
// ** unlock operation fails as well, then the first error code related
|
|
// ** to the first error encountered (the journal finalization one) is
|
|
// ** returned.
|
|
// */
|
|
func _pager_end_transaction(tls *libc.TLS, pPager uintptr, hasSuper int32, bCommit int32) (r int32) {
|
|
var bDelete, rc, rc2, v1 int32
|
|
_, _, _, _ = bDelete, rc, rc2, v1
|
|
rc = SQLITE_OK /* Error code from journal finalization operation */
|
|
rc2 = SQLITE_OK /* Error code from db file unlock operation */
|
|
/* Do nothing if the pager does not have an open write transaction
|
|
** or at least a RESERVED lock. This function may be called when there
|
|
** is no write-transaction active but a RESERVED or greater lock is
|
|
** held under two circumstances:
|
|
**
|
|
** 1. After a successful hot-journal rollback, it is called with
|
|
** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK.
|
|
**
|
|
** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE
|
|
** lock switches back to locking_mode=normal and then executes a
|
|
** read-transaction, this function is called with eState==PAGER_READER
|
|
** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed.
|
|
*/
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) < int32(PAGER_WRITER_LOCKED) && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeLock) < int32(RESERVED_LOCK) {
|
|
return SQLITE_OK
|
|
}
|
|
_releaseAllSavepoints(tls, pPager)
|
|
if (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != uintptr(0) {
|
|
/* Finalize the journal file. */
|
|
if _sqlite3JournalIsInMemory(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd) != 0 {
|
|
/* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */
|
|
_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
|
|
} else {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) == int32(PAGER_JOURNALMODE_TRUNCATE) {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FjournalOff == 0 {
|
|
rc = SQLITE_OK
|
|
} else {
|
|
rc = _sqlite3OsTruncate(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, 0)
|
|
if rc == SQLITE_OK && (*TPager)(unsafe.Pointer(pPager)).FfullSync != 0 {
|
|
/* Make sure the new file size is written into the inode right away.
|
|
** Otherwise the journal might resurrect following a power loss and
|
|
** cause the last transaction to roll back. See
|
|
** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773
|
|
*/
|
|
rc = _sqlite3OsSync(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FsyncFlags))
|
|
}
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = 0
|
|
} else {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) == int32(PAGER_JOURNALMODE_PERSIST) || (*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0 && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) < int32(PAGER_JOURNALMODE_WAL) {
|
|
rc = _zeroJournalHdr(tls, pPager, libc.BoolInt32(hasSuper != 0 || (*TPager)(unsafe.Pointer(pPager)).FtempFile != 0))
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = 0
|
|
} else {
|
|
/* This branch may be executed with Pager.journalMode==MEMORY if
|
|
** a hot-journal was just rolled back. In this case the journal
|
|
** file should be closed and deleted. If this connection writes to
|
|
** the database file, it will do so using an in-memory journal.
|
|
*/
|
|
bDelete = libc.BoolInt32(!((*TPager)(unsafe.Pointer(pPager)).FtempFile != 0))
|
|
_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
|
|
if bDelete != 0 {
|
|
rc = _sqlite3OsDelete(tls, (*TPager)(unsafe.Pointer(pPager)).FpVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FextraSync))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_sqlite3BitvecDestroy(tls, (*TPager)(unsafe.Pointer(pPager)).FpInJournal)
|
|
(*TPager)(unsafe.Pointer(pPager)).FpInJournal = uintptr(0)
|
|
(*TPager)(unsafe.Pointer(pPager)).FnRec = 0
|
|
if rc == SQLITE_OK {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FmemDb != 0 || _pagerFlushOnCommit(tls, pPager, bCommit) != 0 {
|
|
_sqlite3PcacheCleanAll(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache)
|
|
} else {
|
|
_sqlite3PcacheClearWritable(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache)
|
|
}
|
|
_sqlite3PcacheTruncate(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache, (*TPager)(unsafe.Pointer(pPager)).FdbSize)
|
|
}
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
|
|
/* Drop the WAL write-lock, if any. Also, if the connection was in
|
|
** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
|
|
** lock held on the database file.
|
|
*/
|
|
rc2 = _sqlite3WalEndWriteTransaction(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal)
|
|
} else {
|
|
if rc == SQLITE_OK && bCommit != 0 && (*TPager)(unsafe.Pointer(pPager)).FdbFileSize > (*TPager)(unsafe.Pointer(pPager)).FdbSize {
|
|
/* This branch is taken when committing a transaction in rollback-journal
|
|
** mode if the database file on disk is larger than the database image.
|
|
** At this point the journal has been finalized and the transaction
|
|
** successfully committed, but the EXCLUSIVE lock is still held on the
|
|
** file. So it is safe to truncate the database file to its minimum
|
|
** required size. */
|
|
rc = _pager_truncate(tls, pPager, (*TPager)(unsafe.Pointer(pPager)).FdbSize)
|
|
}
|
|
}
|
|
if rc == SQLITE_OK && bCommit != 0 {
|
|
rc = _sqlite3OsFileControl(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, int32(SQLITE_FCNTL_COMMIT_PHASETWO), uintptr(0))
|
|
if rc == int32(SQLITE_NOTFOUND) {
|
|
rc = SQLITE_OK
|
|
}
|
|
}
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0) && (!((*TPager)(unsafe.Pointer(pPager)).FpWal != libc.UintptrFromInt32(0)) || _sqlite3WalExclusiveMode(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal, 0) != 0) {
|
|
rc2 = _pagerUnlockDb(tls, pPager, int32(SHARED_LOCK))
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_READER)
|
|
(*TPager)(unsafe.Pointer(pPager)).FsetSuper = uint8(0)
|
|
if rc == SQLITE_OK {
|
|
v1 = rc2
|
|
} else {
|
|
v1 = rc
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called at the start of every write transaction.
|
|
// ** There must already be a RESERVED or EXCLUSIVE lock on the database
|
|
// ** file when this routine is called.
|
|
// **
|
|
// ** Open the journal file for pager pPager and write a journal header
|
|
// ** to the start of it. If there are active savepoints, open the sub-journal
|
|
// ** as well. This function is only used when the journal file is being
|
|
// ** opened to write a rollback log for a transaction. It is not used
|
|
// ** when opening a hot journal file to roll it back.
|
|
// **
|
|
// ** If the journal file is already open (as it may be in exclusive mode),
|
|
// ** then this function just writes a journal header to the start of the
|
|
// ** already open file.
|
|
// **
|
|
// ** Whether or not the journal file is opened by this function, the
|
|
// ** Pager.pInJournal bitvec structure is allocated.
|
|
// **
|
|
// ** Return SQLITE_OK if everything is successful. Otherwise, return
|
|
// ** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
|
|
// ** an IO error code if opening or writing the journal file fails.
|
|
// */
|
|
func _pager_open_journal(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
var flags, nSpill, rc int32
|
|
var pVfs uintptr
|
|
_, _, _, _ = flags, nSpill, pVfs, rc
|
|
rc = SQLITE_OK /* Return code */
|
|
pVfs = (*TPager)(unsafe.Pointer(pPager)).FpVfs /* Local cache of vfs pointer */
|
|
/* If already in the error state, this function is a no-op. But on
|
|
** the other hand, this routine is never called if we are already in
|
|
** an error state. */
|
|
if (*TPager)(unsafe.Pointer(pPager)).FerrCode != 0 {
|
|
return (*TPager)(unsafe.Pointer(pPager)).FerrCode
|
|
}
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FpWal != libc.UintptrFromInt32(0)) && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) != int32(PAGER_JOURNALMODE_OFF) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FpInJournal = _sqlite3BitvecCreate(tls, (*TPager)(unsafe.Pointer(pPager)).FdbSize)
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpInJournal == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
/* Open the journal file if it is not already open. */
|
|
if !((*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != libc.UintptrFromInt32(0)) {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) == int32(PAGER_JOURNALMODE_MEMORY) {
|
|
_sqlite3MemJournalOpen(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
|
|
} else {
|
|
flags = libc.Int32FromInt32(SQLITE_OPEN_READWRITE) | libc.Int32FromInt32(SQLITE_OPEN_CREATE)
|
|
if (*TPager)(unsafe.Pointer(pPager)).FtempFile != 0 {
|
|
flags = flags | (libc.Int32FromInt32(SQLITE_OPEN_DELETEONCLOSE) | libc.Int32FromInt32(SQLITE_OPEN_TEMP_JOURNAL))
|
|
flags = flags | int32(SQLITE_OPEN_EXCLUSIVE)
|
|
nSpill = _sqlite3Config.FnStmtSpill
|
|
} else {
|
|
flags = flags | int32(SQLITE_OPEN_MAIN_JOURNAL)
|
|
nSpill = _jrnlBufferSize(tls, pPager)
|
|
}
|
|
/* Verify that the database still has the same name as it did when
|
|
** it was originally opened. */
|
|
rc = _databaseIsUnmoved(tls, pPager)
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3JournalOpen(tls, pVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, (*TPager)(unsafe.Pointer(pPager)).Fjfd, flags, nSpill)
|
|
}
|
|
}
|
|
}
|
|
/* Write the first journal header to the journal file and open
|
|
** the sub-journal if necessary.
|
|
*/
|
|
if rc == SQLITE_OK {
|
|
/* TODO: Check if all of these are really required. */
|
|
(*TPager)(unsafe.Pointer(pPager)).FnRec = 0
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = 0
|
|
(*TPager)(unsafe.Pointer(pPager)).FsetSuper = uint8(0)
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalHdr = 0
|
|
rc = _writeJournalHdr(tls, pPager)
|
|
}
|
|
}
|
|
if rc != SQLITE_OK {
|
|
_sqlite3BitvecDestroy(tls, (*TPager)(unsafe.Pointer(pPager)).FpInJournal)
|
|
(*TPager)(unsafe.Pointer(pPager)).FpInJournal = uintptr(0)
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = 0
|
|
} else {
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_WRITER_CACHEMOD)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Memory allocator for parser stack resizing. This is a thin wrapper around
|
|
// ** sqlite3_realloc() that includes a call to sqlite3FaultSim() to facilitate
|
|
// ** testing.
|
|
// */
|
|
func _parserStackRealloc(tls *libc.TLS, pOld uintptr, newSize Tsqlite3_uint64, pParse uintptr) (r uintptr) {
|
|
var p, v1 uintptr
|
|
_, _ = p, v1
|
|
if _sqlite3FaultSim(tls, int32(700)) != 0 {
|
|
v1 = uintptr(0)
|
|
} else {
|
|
v1 = Xsqlite3_realloc(tls, pOld, libc.Int32FromUint64(newSize))
|
|
}
|
|
p = v1
|
|
if p == uintptr(0) {
|
|
_sqlite3OomFault(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb)
|
|
}
|
|
return p
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If there are currently more than nMaxPage pages allocated, try
|
|
// ** to recycle pages to reduce the number allocated to nMaxPage.
|
|
// */
|
|
func _pcache1EnforceMaxPage(tls *libc.TLS, pCache uintptr) {
|
|
var p, pGroup, v1 uintptr
|
|
var v2 bool
|
|
_, _, _, _ = p, pGroup, v1, v2
|
|
pGroup = (*TPCache1)(unsafe.Pointer(pCache)).FpGroup
|
|
for {
|
|
if v2 = (*TPGroup)(unsafe.Pointer(pGroup)).FnPurgeable > (*TPGroup)(unsafe.Pointer(pGroup)).FnMaxPage; v2 {
|
|
v1 = (*TPGroup)(unsafe.Pointer(pGroup)).Flru.FpLruPrev
|
|
p = v1
|
|
}
|
|
if !(v2 && libc.Int32FromUint16((*TPgHdr1)(unsafe.Pointer(v1)).FisAnchor) == 0) {
|
|
break
|
|
}
|
|
_pcache1PinPage(tls, p)
|
|
_pcache1RemoveFromHash(tls, p, int32(1))
|
|
}
|
|
if (*TPCache1)(unsafe.Pointer(pCache)).FnPage == uint32(0) && (*TPCache1)(unsafe.Pointer(pCache)).FpBulk != 0 {
|
|
Xsqlite3_free(tls, (*TPCache1)(unsafe.Pointer(pCache)).FpBulk)
|
|
v1 = libc.UintptrFromInt32(0)
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FpFree = v1
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FpBulk = v1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the sqlite3_pcache.xPagecount method.
|
|
// */
|
|
func _pcache1Pagecount(tls *libc.TLS, p uintptr) (r int32) {
|
|
var n int32
|
|
var pCache uintptr
|
|
_, _ = n, pCache
|
|
pCache = p
|
|
Xsqlite3_mutex_enter(tls, (*TPGroup)(unsafe.Pointer((*TPCache1)(unsafe.Pointer(pCache)).FpGroup)).Fmutex)
|
|
n = libc.Int32FromUint32((*TPCache1)(unsafe.Pointer(pCache)).FnPage)
|
|
Xsqlite3_mutex_leave(tls, (*TPGroup)(unsafe.Pointer((*TPCache1)(unsafe.Pointer(pCache)).FpGroup)).Fmutex)
|
|
return n
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Manage pPage's participation on the dirty list. Bits of the addRemove
|
|
// ** argument determines what operation to do. The 0x01 bit means first
|
|
// ** remove pPage from the dirty list. The 0x02 means add pPage back to
|
|
// ** the dirty list. Doing both moves pPage to the front of the dirty list.
|
|
// */
|
|
func _pcacheManageDirtyList(tls *libc.TLS, pPage uintptr, addRemove Tu8) {
|
|
var p uintptr
|
|
_ = p
|
|
p = (*TPgHdr)(unsafe.Pointer(pPage)).FpCache
|
|
if libc.Int32FromUint8(addRemove)&int32(PCACHE_DIRTYLIST_REMOVE) != 0 {
|
|
/* Update the PCache1.pSynced variable if necessary. */
|
|
if (*TPCache)(unsafe.Pointer(p)).FpSynced == pPage {
|
|
(*TPCache)(unsafe.Pointer(p)).FpSynced = (*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyPrev
|
|
}
|
|
if (*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyNext != 0 {
|
|
(*TPgHdr)(unsafe.Pointer((*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyNext)).FpDirtyPrev = (*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyPrev
|
|
} else {
|
|
(*TPCache)(unsafe.Pointer(p)).FpDirtyTail = (*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyPrev
|
|
}
|
|
if (*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyPrev != 0 {
|
|
(*TPgHdr)(unsafe.Pointer((*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyPrev)).FpDirtyNext = (*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyNext
|
|
} else {
|
|
/* If there are now no dirty pages in the cache, set eCreate to 2.
|
|
** This is an optimization that allows sqlite3PcacheFetch() to skip
|
|
** searching for a dirty page to eject from the cache when it might
|
|
** otherwise have to. */
|
|
(*TPCache)(unsafe.Pointer(p)).FpDirty = (*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyNext
|
|
if (*TPCache)(unsafe.Pointer(p)).FpDirty == uintptr(0) { /*OPTIMIZATION-IF-TRUE*/
|
|
(*TPCache)(unsafe.Pointer(p)).FeCreate = uint8(2)
|
|
}
|
|
}
|
|
}
|
|
if libc.Int32FromUint8(addRemove)&int32(PCACHE_DIRTYLIST_ADD) != 0 {
|
|
(*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyPrev = uintptr(0)
|
|
(*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyNext = (*TPCache)(unsafe.Pointer(p)).FpDirty
|
|
if (*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyNext != 0 {
|
|
(*TPgHdr)(unsafe.Pointer((*TPgHdr)(unsafe.Pointer(pPage)).FpDirtyNext)).FpDirtyPrev = pPage
|
|
} else {
|
|
(*TPCache)(unsafe.Pointer(p)).FpDirtyTail = pPage
|
|
if (*TPCache)(unsafe.Pointer(p)).FbPurgeable != 0 {
|
|
(*TPCache)(unsafe.Pointer(p)).FeCreate = uint8(1)
|
|
}
|
|
}
|
|
(*TPCache)(unsafe.Pointer(p)).FpDirty = pPage
|
|
/* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
|
|
** pSynced to point to it. Checking the NEED_SYNC flag is an
|
|
** optimization, as if pSynced points to a page with the NEED_SYNC
|
|
** flag set sqlite3PcacheFetchStress() searches through all newer
|
|
** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
|
|
if !((*TPCache)(unsafe.Pointer(p)).FpSynced != 0) && 0 == libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(pPage)).Fflags)&int32(PGHDR_NEED_SYNC) {
|
|
(*TPCache)(unsafe.Pointer(p)).FpSynced = pPage
|
|
}
|
|
}
|
|
}
|
|
|
|
var _pgsz = int32(4096)
|
|
|
|
/*
|
|
** Check that the pShmNode->aLock[] array comports with the locking bitmasks
|
|
** held by each client. Return true if it does, or false otherwise. This
|
|
** is to be used in an assert(). e.g.
|
|
**
|
|
** assert( assertLockingArrayOk(pShmNode) );
|
|
*/
|
|
|
|
var _posixIoFinder = uintptr(0)
|
|
|
|
func _posixIoFinderImpl(tls *libc.TLS, z uintptr, p uintptr) (r uintptr) {
|
|
_ = z
|
|
_ = p
|
|
return uintptr(unsafe.Pointer(&_posixIoMethods))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Here are all of the sqlite3_io_methods objects for each of the
|
|
// ** locking strategies. Functions that return pointers to these methods
|
|
// ** are also created.
|
|
// */
|
|
var _posixIoMethods = Tsqlite3_io_methods{
|
|
FiVersion: int32(3),
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Different Unix systems declare open() in different ways. Same use
|
|
// ** open(const char*,int,mode_t). Others use open(const char*,int,...).
|
|
// ** The difference is important when using a pointer to the function.
|
|
// **
|
|
// ** The safest way to deal with the problem is to always use this wrapper
|
|
// ** which always has the same well-defined interface.
|
|
// */
|
|
func _posixOpen(tls *libc.TLS, zFile uintptr, flags int32, mode int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
return libc.Xopen(tls, zFile, flags, libc.VaList(bp+8, mode))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Figure out the best index to use to search a pragma virtual table.
|
|
// **
|
|
// ** There are not really any index choices. But we want to encourage the
|
|
// ** query planner to give == constraints on as many hidden parameters as
|
|
// ** possible, and especially on the first hidden parameter. So return a
|
|
// ** high cost if hidden parameters are unconstrained.
|
|
// */
|
|
func _pragmaVtabBestIndex(tls *libc.TLS, tab uintptr, pIdxInfo uintptr) (r int32) {
|
|
var i, j int32
|
|
var pConstraint, pTab uintptr
|
|
var seen [2]int32
|
|
_, _, _, _, _ = i, j, pConstraint, pTab, seen
|
|
pTab = tab
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedCost = libc.Float64FromInt32(1)
|
|
if libc.Int32FromUint8((*TPragmaVtab)(unsafe.Pointer(pTab)).FnHidden) == 0 {
|
|
return SQLITE_OK
|
|
}
|
|
pConstraint = (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraint
|
|
seen[0] = 0
|
|
seen[int32(1)] = 0
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FnConstraint) {
|
|
break
|
|
}
|
|
if (*Tsqlite3_index_constraint)(unsafe.Pointer(pConstraint)).FiColumn < libc.Int32FromUint8((*TPragmaVtab)(unsafe.Pointer(pTab)).FiHidden) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(pConstraint)).Fop) != int32(SQLITE_INDEX_CONSTRAINT_EQ) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3_index_constraint)(unsafe.Pointer(pConstraint)).Fusable) == 0 {
|
|
return int32(SQLITE_CONSTRAINT)
|
|
}
|
|
j = (*Tsqlite3_index_constraint)(unsafe.Pointer(pConstraint)).FiColumn - libc.Int32FromUint8((*TPragmaVtab)(unsafe.Pointer(pTab)).FiHidden)
|
|
seen[j] = i + int32(1)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
pConstraint += 12
|
|
}
|
|
if seen[0] == 0 {
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedCost = libc.Float64FromInt32(2147483647)
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedRows = int64(2147483647)
|
|
return SQLITE_OK
|
|
}
|
|
j = seen[0] - int32(1)
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(j)*8))).FargvIndex = int32(1)
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(j)*8))).Fomit = uint8(1)
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedCost = libc.Float64FromInt32(20)
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedRows = int64(20)
|
|
if seen[int32(1)] != 0 {
|
|
j = seen[int32(1)] - int32(1)
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(j)*8))).FargvIndex = int32(2)
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(j)*8))).Fomit = uint8(1)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate memory for a temporary buffer needed for printf rendering.
|
|
// **
|
|
// ** If the requested size of the temp buffer is larger than the size
|
|
// ** of the output buffer in pAccum, then cause an SQLITE_TOOBIG error.
|
|
// ** Do the size check before the memory allocation to prevent rogue
|
|
// ** SQL from requesting large allocations using the precision or width
|
|
// ** field of the printf() function.
|
|
// */
|
|
func _printfTempBuf(tls *libc.TLS, pAccum uintptr, n Tsqlite3_int64) (r uintptr) {
|
|
var z uintptr
|
|
_ = z
|
|
if (*Tsqlite3_str)(unsafe.Pointer(pAccum)).FaccError != 0 {
|
|
return uintptr(0)
|
|
}
|
|
if n > libc.Int64FromUint32((*Tsqlite3_str)(unsafe.Pointer(pAccum)).FnAlloc) && n > libc.Int64FromUint32((*Tsqlite3_str)(unsafe.Pointer(pAccum)).FmxAlloc) {
|
|
_sqlite3StrAccumSetError(tls, pAccum, uint8(SQLITE_TOOBIG))
|
|
return uintptr(0)
|
|
}
|
|
z = Xsqlite3_malloc(tls, int32(n))
|
|
if z == uintptr(0) {
|
|
_sqlite3StrAccumSetError(tls, pAccum, uint8(SQLITE_NOMEM))
|
|
}
|
|
return z
|
|
}
|
|
|
|
/*
|
|
** On machines with a small stack size, you can redefine the
|
|
** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired.
|
|
*/
|
|
|
|
/*
|
|
** Hard limit on the precision of floating-point conversions.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read an entry from the pointer map.
|
|
// **
|
|
// ** This routine retrieves the pointer map entry for page 'key', writing
|
|
// ** the type and parent page number to *pEType and *pPgno respectively.
|
|
// ** An error code is returned if something goes wrong, otherwise SQLITE_OK.
|
|
// */
|
|
func _ptrmapGet(tls *libc.TLS, pBt uintptr, key TPgno, pEType uintptr, pPgno uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iPtrmap, offset, rc int32
|
|
var pPtrmap uintptr
|
|
var _ /* pDbPage at bp+0 */ uintptr
|
|
_, _, _, _ = iPtrmap, offset, pPtrmap, rc
|
|
iPtrmap = libc.Int32FromUint32(_ptrmapPageno(tls, pBt, key))
|
|
rc = _sqlite3PagerGet(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, libc.Uint32FromInt32(iPtrmap), bp, 0)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
pPtrmap = _sqlite3PagerGetData(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
offset = libc.Int32FromUint32(libc.Uint32FromInt32(5) * (key - libc.Uint32FromInt32(iPtrmap) - libc.Uint32FromInt32(1)))
|
|
if offset < 0 {
|
|
_sqlite3PagerUnref(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return _sqlite3CorruptError(tls, int32(74364))
|
|
}
|
|
**(**Tu8)(__ccgo_up(pEType)) = **(**Tu8)(__ccgo_up(pPtrmap + uintptr(offset)))
|
|
if pPgno != 0 {
|
|
**(**TPgno)(__ccgo_up(pPgno)) = _sqlite3Get4byte(tls, pPtrmap+uintptr(offset+int32(1)))
|
|
}
|
|
_sqlite3PagerUnref(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pEType))) < int32(1) || libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pEType))) > int32(5) {
|
|
return _sqlite3CorruptError(tls, int32(74372))
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
/*
|
|
** Given a btree page and a cell index (0 means the first cell on
|
|
** the page, 1 means the second cell, and so forth) return a pointer
|
|
** to the cell content.
|
|
**
|
|
** findCellPastPtr() does the same except it skips past the initial
|
|
** 4-byte child pointer found on interior pages, if there is one.
|
|
**
|
|
** This routine works only for pages that do not contain overflow cells.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Given a page number of a regular database page, return the page
|
|
// ** number for the pointer-map page that contains the entry for the
|
|
// ** input page number.
|
|
// **
|
|
// ** Return 0 (not a valid page) for pgno==1 since there is
|
|
// ** no pointer map associated with page 1. The integrity_check logic
|
|
// ** requires that ptrmapPageno(*,1)!=1.
|
|
// */
|
|
func _ptrmapPageno(tls *libc.TLS, pBt uintptr, pgno TPgno) (r TPgno) {
|
|
var iPtrMap, ret TPgno
|
|
var nPagesPerMapPage int32
|
|
_, _, _ = iPtrMap, nPagesPerMapPage, ret
|
|
if pgno < uint32(2) {
|
|
return uint32(0)
|
|
}
|
|
nPagesPerMapPage = libc.Int32FromUint32((*TBtShared)(unsafe.Pointer(pBt)).FusableSize/uint32(5) + uint32(1))
|
|
iPtrMap = (pgno - uint32(2)) / libc.Uint32FromInt32(nPagesPerMapPage)
|
|
ret = iPtrMap*libc.Uint32FromInt32(nPagesPerMapPage) + uint32(2)
|
|
if ret == libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) {
|
|
ret = ret + 1
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Called when a page of data is written to offset iOff of the database
|
|
// ** file while the rbu handle is in capture mode. Record the page number
|
|
// ** of the page being written in the aFrame[] array.
|
|
// */
|
|
func _rbuCaptureDbWrite(tls *libc.TLS, pRbu uintptr, iOff Ti64) (r int32) {
|
|
(**(**TRbuFrame)(__ccgo_up((*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FaFrame + uintptr((*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrame-int32(1))*8))).FiDbPage = libc.Uint32FromInt64(iOff/int64((*Tsqlite3rbu)(unsafe.Pointer(pRbu)).Fpgsz)) + uint32(1)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is called as part of an incremental checkpoint operation. Copy
|
|
// ** a single frame of data from the wal file into the database file, as
|
|
// ** indicated by the RbuFrame object.
|
|
// */
|
|
func _rbuCheckpointFrame(tls *libc.TLS, p uintptr, pFrame uintptr) {
|
|
var iOff Ti64
|
|
var pDb, pWal uintptr
|
|
_, _, _ = iOff, pDb, pWal
|
|
pWal = (*Trbu_file)(unsafe.Pointer((*Trbu_file)(unsafe.Pointer((*Tsqlite3rbu)(unsafe.Pointer(p)).FpTargetFd)).FpWalFd)).FpReal
|
|
pDb = (*Trbu_file)(unsafe.Pointer((*Tsqlite3rbu)(unsafe.Pointer(p)).FpTargetFd)).FpReal
|
|
iOff = libc.Int64FromUint32((*TRbuFrame)(unsafe.Pointer(pFrame)).FiWalFrame-libc.Uint32FromInt32(1))*int64((*Tsqlite3rbu)(unsafe.Pointer(p)).Fpgsz+libc.Int32FromInt32(24)) + int64(32) + int64(24)
|
|
(*Tsqlite3rbu)(unsafe.Pointer(p)).Frc = (*(*func(*libc.TLS, uintptr, uintptr, int32, Tsqlite3_int64) int32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3_io_methods)(unsafe.Pointer((*Tsqlite3_file)(unsafe.Pointer(pWal)).FpMethods)).FxRead})))(tls, pWal, (*Tsqlite3rbu)(unsafe.Pointer(p)).FaBuf, (*Tsqlite3rbu)(unsafe.Pointer(p)).Fpgsz, iOff)
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(p)).Frc != 0 {
|
|
return
|
|
}
|
|
iOff = libc.Int64FromUint32((*TRbuFrame)(unsafe.Pointer(pFrame)).FiDbPage-libc.Uint32FromInt32(1)) * int64((*Tsqlite3rbu)(unsafe.Pointer(p)).Fpgsz)
|
|
(*Tsqlite3rbu)(unsafe.Pointer(p)).Frc = (*(*func(*libc.TLS, uintptr, uintptr, int32, Tsqlite3_int64) int32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3_io_methods)(unsafe.Pointer((*Tsqlite3_file)(unsafe.Pointer(pDb)).FpMethods)).FxWrite})))(tls, pDb, (*Tsqlite3rbu)(unsafe.Pointer(p)).FaBuf, (*Tsqlite3rbu)(unsafe.Pointer(p)).Fpgsz, iOff)
|
|
}
|
|
|
|
/*
|
|
** This value is copied from the definition of ZIPVFS_CTRL_FILE_POINTER
|
|
** in zipvfs.h.
|
|
*/
|
|
|
|
func _rbuPutU16(tls *libc.TLS, aBuf uintptr, iVal Tu16) {
|
|
**(**Tu8)(__ccgo_up(aBuf)) = libc.Uint8FromInt32(libc.Int32FromUint16(iVal) >> int32(8) & int32(0xFF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 1)) = libc.Uint8FromInt32(libc.Int32FromUint16(iVal) >> 0 & int32(0xFF))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the current wal-index header checksum for the target database
|
|
// ** as a 64-bit integer.
|
|
// **
|
|
// ** The checksum is store in the first page of xShmMap memory as an 8-byte
|
|
// ** blob starting at byte offset 40.
|
|
// */
|
|
func _rbuShmChecksum(tls *libc.TLS, p uintptr) (r Ti64) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iRet Ti64
|
|
var pDb uintptr
|
|
var _ /* ptr at bp+0 */ uintptr
|
|
_, _ = iRet, pDb
|
|
iRet = 0
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
pDb = (*Trbu_file)(unsafe.Pointer((*Tsqlite3rbu)(unsafe.Pointer(p)).FpTargetFd)).FpReal
|
|
(*Tsqlite3rbu)(unsafe.Pointer(p)).Frc = (*(*func(*libc.TLS, uintptr, int32, int32, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3_io_methods)(unsafe.Pointer((*Tsqlite3_file)(unsafe.Pointer(pDb)).FpMethods)).FxShmMap})))(tls, pDb, 0, libc.Int32FromInt32(32)*libc.Int32FromInt32(1024), 0, bp)
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
iRet = libc.Int64FromUint64(uint64(libc.AtomicLoadPUint32(**(**uintptr)(__ccgo_up(bp))+libc.UintptrFromInt32(10)*4))<<libc.Int32FromInt32(32) + uint64(libc.AtomicLoadPUint32(**(**uintptr)(__ccgo_up(bp))+11*4)))
|
|
}
|
|
}
|
|
return iRet
|
|
}
|
|
|
|
func _rbuUnlockShm(tls *libc.TLS, p uintptr) {
|
|
var i int32
|
|
var xShmLock uintptr
|
|
_, _ = i, xShmLock
|
|
if (*Trbu_file)(unsafe.Pointer(p)).FpRbu != 0 {
|
|
xShmLock = (*Tsqlite3_io_methods)(unsafe.Pointer((*Tsqlite3_file)(unsafe.Pointer((*Trbu_file)(unsafe.Pointer(p)).FpReal)).FpMethods)).FxShmLock
|
|
i = 0
|
|
for {
|
|
if !(i < int32(SQLITE_SHM_NLOCK)) {
|
|
break
|
|
}
|
|
if libc.Uint32FromInt32(libc.Int32FromInt32(1)<<i)&(*Tsqlite3rbu)(unsafe.Pointer((*Trbu_file)(unsafe.Pointer(p)).FpRbu)).FmLock != 0 {
|
|
(*(*func(*libc.TLS, uintptr, int32, int32, int32) int32)(unsafe.Pointer(&struct{ uintptr }{xShmLock})))(tls, (*Trbu_file)(unsafe.Pointer(p)).FpReal, i, int32(1), libc.Int32FromInt32(SQLITE_SHM_UNLOCK)|libc.Int32FromInt32(SQLITE_SHM_EXCLUSIVE))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*Tsqlite3rbu)(unsafe.Pointer((*Trbu_file)(unsafe.Pointer(p)).FpRbu)).FmLock = uint32(0)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Functions to deserialize a 16 bit integer, 32 bit real number and
|
|
// ** 64 bit integer. The deserialized value is returned.
|
|
// */
|
|
func _readInt16(tls *libc.TLS, p uintptr) (r int32) {
|
|
return libc.Int32FromUint8(**(**Tu8)(__ccgo_up(p)))<<int32(8) + libc.Int32FromUint8(**(**Tu8)(__ccgo_up(p + 1)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return non-zero if the table pTab in database iDb or any of its indices
|
|
// ** have been opened at any point in the VDBE program. This is used to see if
|
|
// ** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
|
// ** run without using a temporary table for the results of the SELECT.
|
|
// */
|
|
func _readsTable(tls *libc.TLS, p uintptr, iDb int32, pTab uintptr) (r int32) {
|
|
var i, iEnd int32
|
|
var pIndex, pOp, pVTab, v, v1 uintptr
|
|
var tnum TPgno
|
|
_, _, _, _, _, _, _, _ = i, iEnd, pIndex, pOp, pVTab, tnum, v, v1
|
|
v = _sqlite3GetVdbe(tls, p)
|
|
iEnd = _sqlite3VdbeCurrentAddr(tls, v)
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) {
|
|
v1 = _sqlite3GetVTable(tls, (*TParse)(unsafe.Pointer(p)).Fdb, pTab)
|
|
} else {
|
|
v1 = uintptr(0)
|
|
}
|
|
pVTab = v1
|
|
i = int32(1)
|
|
for {
|
|
if !(i < iEnd) {
|
|
break
|
|
}
|
|
pOp = _sqlite3VdbeGetOp(tls, v, i)
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode) == int32(OP_OpenRead) && (*TVdbeOp)(unsafe.Pointer(pOp)).Fp3 == iDb {
|
|
tnum = libc.Uint32FromInt32((*TVdbeOp)(unsafe.Pointer(pOp)).Fp2)
|
|
if tnum == (*TTable)(unsafe.Pointer(pTab)).Ftnum {
|
|
return int32(1)
|
|
}
|
|
pIndex = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIndex != 0) {
|
|
break
|
|
}
|
|
if tnum == (*TIndex)(unsafe.Pointer(pIndex)).Ftnum {
|
|
return int32(1)
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
pIndex = (*TIndex)(unsafe.Pointer(pIndex)).FpNext
|
|
}
|
|
}
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode) == int32(OP_VOpen) && *(*uintptr)(unsafe.Pointer(pOp + 16)) == pVTab {
|
|
return int32(1)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Release a unixInodeInfo structure previously allocated by findInodeInfo().
|
|
// **
|
|
// ** The global mutex must be held when this routine is called, but the mutex
|
|
// ** on the inode being deleted must NOT be held.
|
|
// */
|
|
func _releaseInodeInfo(tls *libc.TLS, pFile uintptr) {
|
|
var pInode uintptr
|
|
_ = pInode
|
|
pInode = (*TunixFile)(unsafe.Pointer(pFile)).FpInode
|
|
if pInode != 0 {
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FnRef = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FnRef - 1
|
|
if (*TunixInodeInfo)(unsafe.Pointer(pInode)).FnRef == 0 {
|
|
Xsqlite3_mutex_enter(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
|
|
_closePendingFds(tls, pFile)
|
|
Xsqlite3_mutex_leave(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
|
|
if (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpPrev != 0 {
|
|
(*TunixInodeInfo)(unsafe.Pointer((*TunixInodeInfo)(unsafe.Pointer(pInode)).FpPrev)).FpNext = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpNext
|
|
} else {
|
|
_inodeList = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpNext
|
|
}
|
|
if (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpNext != 0 {
|
|
(*TunixInodeInfo)(unsafe.Pointer((*TunixInodeInfo)(unsafe.Pointer(pInode)).FpNext)).FpPrev = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpPrev
|
|
}
|
|
Xsqlite3_mutex_free(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
|
|
Xsqlite3_free(tls, pInode)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is a Walker select callback. It does nothing. It is only required
|
|
// ** because without a dummy callback, sqlite3WalkExpr() and similar do not
|
|
// ** descend into sub-select statements.
|
|
// */
|
|
func _renameColumnSelectCb(tls *libc.TLS, pWalker uintptr, p uintptr) (r int32) {
|
|
if (*TSelect)(unsafe.Pointer(p)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_View)|libc.Int32FromInt32(SF_CopyCte)) != 0 {
|
|
return int32(WRC_Prune)
|
|
}
|
|
_renameWalkWith(tls, pWalker, p)
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Resolve an expression that was part of an ATTACH or DETACH statement. This
|
|
// ** is slightly different from resolving a normal SQL expression, because simple
|
|
// ** identifiers are treated as strings, not possible column names or aliases.
|
|
// **
|
|
// ** i.e. if the parser sees:
|
|
// **
|
|
// ** ATTACH DATABASE abc AS def
|
|
// **
|
|
// ** it treats the two expressions as literal strings 'abc' and 'def' instead of
|
|
// ** looking for columns of the same name.
|
|
// **
|
|
// ** This only applies to the root node of pExpr, so the statement:
|
|
// **
|
|
// ** ATTACH DATABASE abc||def AS 'db2'
|
|
// **
|
|
// ** will fail because neither abc or def can be resolved.
|
|
// */
|
|
func _resolveAttachExpr(tls *libc.TLS, pName uintptr, pExpr uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
rc = SQLITE_OK
|
|
if pExpr != 0 {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_ID) {
|
|
rc = _sqlite3ResolveExprNames(tls, pName, pExpr)
|
|
} else {
|
|
(*TExpr)(unsafe.Pointer(pExpr)).Fop = uint8(TK_STRING)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Rtree virtual table module xClose method.
|
|
// */
|
|
func _rtreeClose(tls *libc.TLS, cur uintptr) (r int32) {
|
|
var pCsr, pRtree uintptr
|
|
_, _ = pCsr, pRtree
|
|
pRtree = (*Tsqlite3_vtab_cursor)(unsafe.Pointer(cur)).FpVtab
|
|
pCsr = cur
|
|
_resetCursor(tls, pCsr)
|
|
Xsqlite3_finalize(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux)
|
|
Xsqlite3_free(tls, pCsr)
|
|
(*TRtree)(unsafe.Pointer(pRtree)).FnCursor = (*TRtree)(unsafe.Pointer(pRtree)).FnCursor - 1
|
|
if (*TRtree)(unsafe.Pointer(pRtree)).FnCursor == uint32(0) && libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FinWrTrans) == 0 {
|
|
_nodeBlobReset(tls, pRtree)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Rtree virtual table module xEof method.
|
|
// **
|
|
// ** Return non-zero if the cursor does not currently point to a valid
|
|
// ** record (i.e if the scan has finished), or zero otherwise.
|
|
// */
|
|
func _rtreeEof(tls *libc.TLS, cur uintptr) (r int32) {
|
|
var pCsr uintptr
|
|
_ = pCsr
|
|
pCsr = cur
|
|
return libc.Int32FromUint8((*TRtreeCursor)(unsafe.Pointer(pCsr)).FatEOF)
|
|
}
|
|
|
|
/*
|
|
** Convert raw bits from the on-disk RTree record into a coordinate value.
|
|
** The on-disk format is big-endian and needs to be converted for little-
|
|
** endian platforms. The on-disk record stores integer coordinates if
|
|
** eInt is true and it stores 32-bit floating point records if eInt is
|
|
** false. a[] is the four bytes of the on-disk record to be decoded.
|
|
** Store the results in "r".
|
|
**
|
|
** There are five versions of this macro. The last one is generic. The
|
|
** other four are various architectures-specific optimizations.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Rtree virtual table module xRowid method.
|
|
// */
|
|
func _rtreeRowid(tls *libc.TLS, pVtabCursor uintptr, pRowid uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var p, pCsr, pNode uintptr
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _ = p, pCsr, pNode
|
|
pCsr = pVtabCursor
|
|
p = _rtreeSearchPointFirst(tls, pCsr)
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
pNode = _rtreeNodeOfFirstSearchPoint(tls, pCsr, bp)
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK && p != 0 {
|
|
if libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(p)).FiCell) >= _readInt16(tls, (*TRtreeNode)(unsafe.Pointer(pNode)).FzData+2) {
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_ABORT)
|
|
} else {
|
|
**(**Tsqlite_int64)(__ccgo_up(pRowid)) = _nodeGetRowid(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).Fbase.FpVtab, pNode, libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(p)).FiCell))
|
|
}
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compare two search points. Return negative, zero, or positive if the first
|
|
// ** is less than, equal to, or greater than the second.
|
|
// **
|
|
// ** The rScore is the primary key. Smaller rScore values come first.
|
|
// ** If the rScore is a tie, then use iLevel as the tie breaker with smaller
|
|
// ** iLevel values coming first. In this way, if rScore is the same for all
|
|
// ** SearchPoints, then iLevel becomes the deciding factor and the result
|
|
// ** is a depth-first search, which is the desired default behavior.
|
|
// */
|
|
func _rtreeSearchPointCompare(tls *libc.TLS, pA uintptr, pB uintptr) (r int32) {
|
|
if (*TRtreeSearchPoint)(unsafe.Pointer(pA)).FrScore < (*TRtreeSearchPoint)(unsafe.Pointer(pB)).FrScore {
|
|
return -int32(1)
|
|
}
|
|
if (*TRtreeSearchPoint)(unsafe.Pointer(pA)).FrScore > (*TRtreeSearchPoint)(unsafe.Pointer(pB)).FrScore {
|
|
return +libc.Int32FromInt32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(pA)).FiLevel) < libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(pB)).FiLevel) {
|
|
return -int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(pA)).FiLevel) > libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(pB)).FiLevel) {
|
|
return +libc.Int32FromInt32(1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is the collating function named "RTRIM" which is always
|
|
// ** available. Ignore trailing spaces.
|
|
// */
|
|
func _rtrimCollFunc(tls *libc.TLS, pUser uintptr, nKey1 int32, pKey1 uintptr, nKey2 int32, pKey2 uintptr) (r int32) {
|
|
var pK1, pK2 uintptr
|
|
_, _ = pK1, pK2
|
|
pK1 = pKey1
|
|
pK2 = pKey2
|
|
for nKey1 != 0 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pK1 + uintptr(nKey1-int32(1))))) == int32(' ') {
|
|
nKey1 = nKey1 - 1
|
|
}
|
|
for nKey2 != 0 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pK2 + uintptr(nKey2-int32(1))))) == int32(' ') {
|
|
nKey2 = nKey2 - 1
|
|
}
|
|
return _binCollFunc(tls, pUser, nKey1, pKey1, nKey2, pKey2)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Save the current cursor position in the variables BtCursor.nKey
|
|
// ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
|
|
// **
|
|
// ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
|
|
// ** prior to calling this routine.
|
|
// */
|
|
func _saveCursorPosition(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
var rc int32
|
|
var v1 uintptr
|
|
_, _ = rc, v1
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FcurFlags)&int32(BTCF_Pinned) != 0 {
|
|
return libc.Int32FromInt32(SQLITE_CONSTRAINT) | libc.Int32FromInt32(11)<<libc.Int32FromInt32(8)
|
|
}
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == int32(CURSOR_SKIPNEXT) {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_VALID)
|
|
} else {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FskipNext = 0
|
|
}
|
|
rc = _saveCursorKey(tls, pCur)
|
|
if rc == SQLITE_OK {
|
|
_btreeReleaseAllCursorPages(tls, pCur)
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_REQUIRESEEK)
|
|
}
|
|
v1 = pCur + 1
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(BTCF_ValidNKey) | libc.Int32FromInt32(BTCF_ValidOvfl) | libc.Int32FromInt32(BTCF_AtLast)))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* This helper routine to saveAllCursors does the actual work of saving
|
|
// ** the cursors if and when a cursor is found that actually requires saving.
|
|
// ** The common case is that no cursors need to be saved, so this routine is
|
|
// ** broken out from its caller to avoid unnecessary stack pointer movement.
|
|
// */
|
|
func _saveCursorsOnList(tls *libc.TLS, p uintptr, iRoot TPgno, pExcept uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
for cond := true; cond; cond = p != 0 {
|
|
if p != pExcept && (uint32(0) == iRoot || (*TBtCursor)(unsafe.Pointer(p)).FpgnoRoot == iRoot) {
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(p)).FeState) == CURSOR_VALID || libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(p)).FeState) == int32(CURSOR_SKIPNEXT) {
|
|
rc = _saveCursorPosition(tls, p)
|
|
if SQLITE_OK != rc {
|
|
return rc
|
|
}
|
|
} else {
|
|
_btreeReleaseAllCursorPages(tls, p)
|
|
}
|
|
}
|
|
p = (*TBtCursor)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
// ** called. Otherwse, it appends the serialized version of the value stored
|
|
// ** in column iCol of the row that SQL statement pStmt currently points
|
|
// ** to to the buffer.
|
|
// */
|
|
func _sessionAppendCol(tls *libc.TLS, p uintptr, pStmt uintptr, iCol int32, pRc uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var eType, nByte int32
|
|
var i Tsqlite3_int64
|
|
var r float64
|
|
var z uintptr
|
|
var _ /* aBuf at bp+0 */ [8]Tu8
|
|
_, _, _, _, _ = eType, i, nByte, r, z
|
|
if **(**int32)(__ccgo_up(pRc)) == SQLITE_OK {
|
|
eType = Xsqlite3_column_type(tls, pStmt, iCol)
|
|
_sessionAppendByte(tls, p, libc.Uint8FromInt32(eType), pRc)
|
|
if eType == int32(SQLITE_INTEGER) || eType == int32(SQLITE_FLOAT) {
|
|
if eType == int32(SQLITE_INTEGER) {
|
|
i = Xsqlite3_column_int64(tls, pStmt, iCol)
|
|
_sessionPutI64(tls, bp, i)
|
|
} else {
|
|
r = Xsqlite3_column_double(tls, pStmt, iCol)
|
|
_sessionPutDouble(tls, bp, r)
|
|
}
|
|
_sessionAppendBlob(tls, p, bp, int32(8), pRc)
|
|
}
|
|
if eType == int32(SQLITE_BLOB) || eType == int32(SQLITE_TEXT) {
|
|
if eType == int32(SQLITE_BLOB) {
|
|
z = Xsqlite3_column_blob(tls, pStmt, iCol)
|
|
} else {
|
|
z = Xsqlite3_column_text(tls, pStmt, iCol)
|
|
}
|
|
nByte = Xsqlite3_column_bytes(tls, pStmt, iCol)
|
|
if z != 0 || eType == int32(SQLITE_BLOB) && nByte == 0 {
|
|
_sessionAppendVarint(tls, p, nByte, pRc)
|
|
_sessionAppendBlob(tls, p, z, nByte, pRc)
|
|
} else {
|
|
**(**int32)(__ccgo_up(pRc)) = int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Ensure that there is room in the buffer to append nByte bytes of data.
|
|
// ** If not, use sqlite3_realloc() to grow the buffer so that there is.
|
|
// **
|
|
// ** If successful, return zero. Otherwise, if an OOM condition is encountered,
|
|
// ** set *pRc to SQLITE_NOMEM and return non-zero.
|
|
// */
|
|
func _sessionBufferGrow(tls *libc.TLS, p uintptr, nByte Ti64, pRc uintptr) (r int32) {
|
|
var aNew uintptr
|
|
var nNew, nReq Ti64
|
|
var v1 int32
|
|
_, _, _, _ = aNew, nNew, nReq, v1
|
|
nReq = int64((*TSessionBuffer)(unsafe.Pointer(p)).FnBuf) + nByte
|
|
if **(**int32)(__ccgo_up(pRc)) == SQLITE_OK && nReq > int64((*TSessionBuffer)(unsafe.Pointer(p)).FnAlloc) {
|
|
if (*TSessionBuffer)(unsafe.Pointer(p)).FnAlloc != 0 {
|
|
v1 = (*TSessionBuffer)(unsafe.Pointer(p)).FnAlloc
|
|
} else {
|
|
v1 = int32(128)
|
|
}
|
|
nNew = int64(v1)
|
|
for cond := true; cond; cond = nNew < nReq {
|
|
nNew = nNew * int64(2)
|
|
}
|
|
/* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation
|
|
** of sqlite3_realloc64(). Allocations greater than this size in bytes
|
|
** always fail. It is used here to ensure that this routine can always
|
|
** allocate up to this limit - instead of up to the largest power of
|
|
** two smaller than the limit. */
|
|
if nNew > int64(libc.Int32FromInt32(0x7FFFFF00)-libc.Int32FromInt32(1)) {
|
|
nNew = int64(libc.Int32FromInt32(0x7FFFFF00) - libc.Int32FromInt32(1))
|
|
if nNew < nReq {
|
|
**(**int32)(__ccgo_up(pRc)) = int32(SQLITE_NOMEM)
|
|
return int32(1)
|
|
}
|
|
}
|
|
aNew = Xsqlite3_realloc64(tls, (*TSessionBuffer)(unsafe.Pointer(p)).FaBuf, libc.Uint64FromInt64(nNew))
|
|
if uintptr(0) == aNew {
|
|
**(**int32)(__ccgo_up(pRc)) = int32(SQLITE_NOMEM)
|
|
} else {
|
|
(*TSessionBuffer)(unsafe.Pointer(p)).FaBuf = aNew
|
|
(*TSessionBuffer)(unsafe.Pointer(p)).FnAlloc = int32(nNew)
|
|
}
|
|
}
|
|
return libc.BoolInt32(**(**int32)(__ccgo_up(pRc)) != SQLITE_OK)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Based on the primary key values stored in change aRecord, calculate a
|
|
// ** hash key. Assume the has table has nBucket buckets. The hash keys
|
|
// ** calculated by this function are compatible with those calculated by
|
|
// ** sessionPreupdateHash().
|
|
// **
|
|
// ** The bPkOnly argument is non-zero if the record at aRecord[] is from
|
|
// ** a patchset DELETE. In this case the non-PK fields are omitted entirely.
|
|
// */
|
|
func _sessionChangeHash(tls *libc.TLS, pTab uintptr, bPkOnly int32, aRecord uintptr, nBucket int32) (r uint32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var a, v2 uintptr
|
|
var eType, i, isPK int32
|
|
var h uint32
|
|
var _ /* n at bp+0 */ int32
|
|
_, _, _, _, _, _ = a, eType, h, i, isPK, v2
|
|
h = uint32(0) /* Used to iterate through columns */
|
|
a = aRecord /* Used to iterate through change record */
|
|
i = 0
|
|
for {
|
|
if !(i < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol) {
|
|
break
|
|
}
|
|
isPK = libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TSessionTable)(unsafe.Pointer(pTab)).FabPK + uintptr(i))))
|
|
if bPkOnly != 0 && isPK == 0 {
|
|
goto _1
|
|
}
|
|
if isPK != 0 {
|
|
v2 = a
|
|
a = a + 1
|
|
eType = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v2)))
|
|
h = _sessionHashAppendType(tls, h, eType)
|
|
if eType == int32(SQLITE_INTEGER) || eType == int32(SQLITE_FLOAT) {
|
|
h = _sessionHashAppendI64(tls, h, _sessionGetI64(tls, a))
|
|
a = a + uintptr(8)
|
|
} else {
|
|
if eType == int32(SQLITE_TEXT) || eType == int32(SQLITE_BLOB) {
|
|
a = a + uintptr(_sessionVarintGet(tls, a, bp))
|
|
h = _sessionHashAppendBlob(tls, h, **(**int32)(__ccgo_up(bp)), a)
|
|
a = a + uintptr(**(**int32)(__ccgo_up(bp)))
|
|
}
|
|
}
|
|
/* It should not be possible for eType to be SQLITE_NULL or 0x00 here,
|
|
** as the session module does not record changes for rows with NULL
|
|
** values stored in primary key columns. But a corrupt changesets
|
|
** may contain such a value. */
|
|
} else {
|
|
a = a + uintptr(_sessionSerialLen(tls, a))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return h % libc.Uint32FromInt32(nBucket)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The input pointer currently points to the first byte of the first field
|
|
// ** of a record consisting of nCol columns. This function ensures the entire
|
|
// ** record is buffered. It does not move the input pointer.
|
|
// **
|
|
// ** If successful, SQLITE_OK is returned and *pnByte is set to the size of
|
|
// ** the record in bytes. Otherwise, an SQLite error code is returned. The
|
|
// ** final value of *pnByte is undefined in this case.
|
|
// */
|
|
func _sessionChangesetBufferRecord(tls *libc.TLS, pIn uintptr, nCol int32, pnByte uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var eType, i, nRem, rc int32
|
|
var nByte, v2 Ti64
|
|
var _ /* n at bp+0 */ int32
|
|
_, _, _, _, _, _ = eType, i, nByte, nRem, rc, v2
|
|
rc = SQLITE_OK
|
|
nByte = 0
|
|
i = 0
|
|
for {
|
|
if !(rc == SQLITE_OK && i < nCol) {
|
|
break
|
|
}
|
|
rc = _sessionInputBuffer(tls, pIn, int32(nByte+int64(10)))
|
|
if rc == SQLITE_OK {
|
|
v2 = nByte
|
|
nByte = nByte + 1
|
|
eType = libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TSessionInput)(unsafe.Pointer(pIn)).FaData + uintptr(int64((*TSessionInput)(unsafe.Pointer(pIn)).FiNext)+v2))))
|
|
if eType == int32(SQLITE_TEXT) || eType == int32(SQLITE_BLOB) {
|
|
nRem = int32(int64((*TSessionInput)(unsafe.Pointer(pIn)).FnData) - (int64((*TSessionInput)(unsafe.Pointer(pIn)).FiNext) + nByte))
|
|
nByte = nByte + int64(_sessionVarintGetSafe(tls, (*TSessionInput)(unsafe.Pointer(pIn)).FaData+uintptr(int64((*TSessionInput)(unsafe.Pointer(pIn)).FiNext)+nByte), nRem, bp))
|
|
nByte = nByte + int64(**(**int32)(__ccgo_up(bp)))
|
|
rc = _sessionInputBuffer(tls, pIn, int32(nByte))
|
|
} else {
|
|
if eType == int32(SQLITE_INTEGER) || eType == int32(SQLITE_FLOAT) {
|
|
nByte = nByte + int64(8)
|
|
} else {
|
|
if eType != 0 && eType != int32(SQLITE_NULL) {
|
|
rc = _sqlite3CorruptError(tls, int32(237456))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if rc == SQLITE_OK && int64((*TSessionInput)(unsafe.Pointer(pIn)).FiNext)+nByte > int64((*TSessionInput)(unsafe.Pointer(pIn)).FnData) {
|
|
rc = _sqlite3CorruptError(tls, int32(237460))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(pnByte)) = int32(nByte)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read a 64-bit big-endian integer value from buffer aRec[]. Return
|
|
// ** the value read.
|
|
// */
|
|
func _sessionGetI64(tls *libc.TLS, aRec uintptr) (r Tsqlite3_int64) {
|
|
var x Tu64
|
|
var y Tu32
|
|
_, _ = x, y
|
|
x = uint64(uint32(**(**Tu8)(__ccgo_up(aRec)))<<libc.Int32FromInt32(24) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aRec + 1)))<<libc.Int32FromInt32(16)) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aRec + 2)))<<libc.Int32FromInt32(8)) | uint32(**(**Tu8)(__ccgo_up(aRec + 3))))
|
|
y = uint32(**(**Tu8)(__ccgo_up(aRec + libc.UintptrFromInt32(4))))<<libc.Int32FromInt32(24) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aRec + libc.UintptrFromInt32(4) + 1)))<<libc.Int32FromInt32(16)) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aRec + libc.UintptrFromInt32(4) + 2)))<<libc.Int32FromInt32(8)) | uint32(**(**Tu8)(__ccgo_up(aRec + libc.UintptrFromInt32(4) + 3)))
|
|
x = x<<libc.Int32FromInt32(32) + uint64(y)
|
|
return libc.Int64FromUint64(x)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append the hash of the 64-bit integer passed as the second argument to the
|
|
// ** hash-key value passed as the first. Return the new hash-key value.
|
|
// */
|
|
func _sessionHashAppendI64(tls *libc.TLS, h uint32, i Ti64) (r uint32) {
|
|
h = h<<int32(3) ^ h ^ libc.Uint32FromInt64(i&libc.Int64FromUint32(0xFFFFFFFF))
|
|
return h<<int32(3) ^ h ^ libc.Uint32FromInt64(i>>libc.Int32FromInt32(32)&libc.Int64FromUint32(0xFFFFFFFF))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append the hash of the data type passed as the second argument to the
|
|
// ** hash-key value passed as the first. Return the new hash-key value.
|
|
// */
|
|
func _sessionHashAppendType(tls *libc.TLS, h uint32, eType int32) (r uint32) {
|
|
return h<<int32(3) ^ h ^ libc.Uint32FromInt32(eType)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Write a 64-bit big-endian integer value to the buffer aBuf[].
|
|
// */
|
|
func _sessionPutI64(tls *libc.TLS, aBuf uintptr, i Tsqlite3_int64) {
|
|
**(**Tu8)(__ccgo_up(aBuf)) = libc.Uint8FromInt64(i >> libc.Int32FromInt32(56) & int64(0xFF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 1)) = libc.Uint8FromInt64(i >> libc.Int32FromInt32(48) & int64(0xFF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 2)) = libc.Uint8FromInt64(i >> libc.Int32FromInt32(40) & int64(0xFF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 3)) = libc.Uint8FromInt64(i >> libc.Int32FromInt32(32) & int64(0xFF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 4)) = libc.Uint8FromInt64(i >> libc.Int32FromInt32(24) & int64(0xFF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 5)) = libc.Uint8FromInt64(i >> libc.Int32FromInt32(16) & int64(0xFF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 6)) = libc.Uint8FromInt64(i >> libc.Int32FromInt32(8) & int64(0xFF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 7)) = libc.Uint8FromInt64(i >> libc.Int32FromInt32(0) & int64(0xFF))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The buffer that the argument points to contains a serialized SQL value.
|
|
// ** Return the number of bytes of space occupied by the value (including
|
|
// ** the type byte).
|
|
// */
|
|
func _sessionSerialLen(tls *libc.TLS, a uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var e int32
|
|
var _ /* n at bp+0 */ int32
|
|
_ = e
|
|
e = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(a)))
|
|
if e == int32(SQLITE_INTEGER) || e == int32(SQLITE_FLOAT) {
|
|
return int32(9)
|
|
}
|
|
if e == int32(SQLITE_TEXT) || e == int32(SQLITE_BLOB) {
|
|
return _sessionVarintGet(tls, a+1, bp) + int32(1) + **(**int32)(__ccgo_up(bp))
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** When this function is called, *ppRec points to the start of a record
|
|
// ** that contains nCol values. This function advances the pointer *ppRec
|
|
// ** until it points to the byte immediately following that record.
|
|
// */
|
|
func _sessionSkipRecord(tls *libc.TLS, ppRec uintptr, nCol int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var aRec, v2 uintptr
|
|
var eType, i int32
|
|
var _ /* nByte at bp+0 */ int32
|
|
_, _, _, _ = aRec, eType, i, v2
|
|
aRec = **(**uintptr)(__ccgo_up(ppRec))
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
v2 = aRec
|
|
aRec = aRec + 1
|
|
eType = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v2)))
|
|
if eType == int32(SQLITE_TEXT) || eType == int32(SQLITE_BLOB) {
|
|
aRec = aRec + uintptr(_sessionVarintGet(tls, aRec, bp))
|
|
aRec = aRec + uintptr(**(**int32)(__ccgo_up(bp)))
|
|
} else {
|
|
if eType == int32(SQLITE_INTEGER) || eType == int32(SQLITE_FLOAT) {
|
|
aRec = aRec + uintptr(8)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppRec)) = aRec
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read a varint value from aBuf[] into *piVal. Return the number of
|
|
// ** bytes read.
|
|
// */
|
|
func _sessionVarintGet(tls *libc.TLS, aBuf uintptr, piVal uintptr) (r int32) {
|
|
var v1 int32
|
|
_ = v1
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aBuf))) < libc.Int32FromUint8(libc.Uint8FromInt32(0x80)) {
|
|
**(**int32)(__ccgo_up(piVal)) = libc.Int32FromUint32(uint32(**(**Tu8)(__ccgo_up(aBuf))))
|
|
v1 = libc.Int32FromInt32(1)
|
|
} else {
|
|
v1 = libc.Int32FromUint8(_sqlite3GetVarint32(tls, aBuf, piVal))
|
|
}
|
|
return libc.Int32FromUint8(libc.Uint8FromInt32(v1))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the number of bytes required to store value iVal as a varint.
|
|
// */
|
|
func _sessionVarintLen(tls *libc.TLS, iVal int32) (r int32) {
|
|
return _sqlite3VarintLen(tls, libc.Uint64FromInt32(iVal))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Write a varint with value iVal into the buffer at aBuf. Return the
|
|
// ** number of bytes written.
|
|
// */
|
|
func _sessionVarintPut(tls *libc.TLS, aBuf uintptr, iVal int32) (r int32) {
|
|
var v1 int32
|
|
_ = v1
|
|
if libc.Uint32FromInt32(iVal) < libc.Uint32FromInt32(0x80) {
|
|
**(**Tu8)(__ccgo_up(aBuf)) = libc.Uint8FromInt32(iVal)
|
|
v1 = libc.Int32FromInt32(1)
|
|
} else {
|
|
v1 = _sqlite3PutVarint(tls, aBuf, libc.Uint64FromInt32(iVal))
|
|
}
|
|
return libc.Int32FromUint8(libc.Uint8FromInt32(v1))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5)
|
|
// ** so that a subsequent copy will not be merged into this one.
|
|
// */
|
|
func _setDoNotMergeFlagOnCopy(tls *libc.TLS, v uintptr) {
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(_sqlite3VdbeGetLastOp(tls, v))).Fopcode) == int32(OP_Copy) {
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(1)) /* Tag trailing OP_Copy as not mergeable */
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add the file descriptor used by file handle pFile to the corresponding
|
|
// ** pUnused list.
|
|
// */
|
|
func _setPendingFd(tls *libc.TLS, pFile uintptr) {
|
|
var p, pInode uintptr
|
|
_, _ = p, pInode
|
|
pInode = (*TunixFile)(unsafe.Pointer(pFile)).FpInode
|
|
p = (*TunixFile)(unsafe.Pointer(pFile)).FpPreallocatedUnused
|
|
(*TUnixUnusedFd)(unsafe.Pointer(p)).FpNext = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpUnused
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FpUnused = p
|
|
(*TunixFile)(unsafe.Pointer(pFile)).Fh = -int32(1)
|
|
(*TunixFile)(unsafe.Pointer(pFile)).FpPreallocatedUnused = uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set result column names for a pragma.
|
|
// */
|
|
func _setPragmaResultColumnNames(tls *libc.TLS, v uintptr, pPragma uintptr) {
|
|
var i, j, v1 int32
|
|
var n Tu8
|
|
_, _, _, _ = i, j, n, v1
|
|
n = (*TPragmaName)(unsafe.Pointer(pPragma)).FnPragCName
|
|
if libc.Int32FromUint8(n) == 0 {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = libc.Int32FromUint8(n)
|
|
}
|
|
_sqlite3VdbeSetNumCols(tls, v, v1)
|
|
if libc.Int32FromUint8(n) == 0 {
|
|
_sqlite3VdbeSetColName(tls, v, 0, COLNAME_NAME, (*TPragmaName)(unsafe.Pointer(pPragma)).FzName, libc.UintptrFromInt32(0))
|
|
} else {
|
|
i = 0
|
|
j = libc.Int32FromUint8((*TPragmaName)(unsafe.Pointer(pPragma)).FiPragCName)
|
|
for {
|
|
if !(i < libc.Int32FromUint8(n)) {
|
|
break
|
|
}
|
|
_sqlite3VdbeSetColName(tls, v, i, COLNAME_NAME, _pragCName[j], libc.UintptrFromInt32(0))
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
j = j + 1
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the value of the Pager.sectorSize variable for the given
|
|
// ** pager based on the value returned by the xSectorSize method
|
|
// ** of the open database file. The sector size will be used
|
|
// ** to determine the size and alignment of journal header and
|
|
// ** super-journal pointers within created journal files.
|
|
// **
|
|
// ** For temporary files the effective sector size is always 512 bytes.
|
|
// **
|
|
// ** Otherwise, for non-temporary files, the effective sector size is
|
|
// ** the value returned by the xSectorSize() method rounded up to 32 if
|
|
// ** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it
|
|
// ** is greater than MAX_SECTOR_SIZE.
|
|
// **
|
|
// ** If the file has the SQLITE_IOCAP_POWERSAFE_OVERWRITE property, then set
|
|
// ** the effective sector size to its minimum value (512). The purpose of
|
|
// ** pPager->sectorSize is to define the "blast radius" of bytes that
|
|
// ** might change if a crash occurs while writing to a single byte in
|
|
// ** that range. But with POWERSAFE_OVERWRITE, the blast radius is zero
|
|
// ** (that is what POWERSAFE_OVERWRITE means), so we minimize the sector
|
|
// ** size. For backwards compatibility of the rollback journal file format,
|
|
// ** we cannot reduce the effective sector size below 512.
|
|
// */
|
|
func _setSectorSize(tls *libc.TLS, pPager uintptr) {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FtempFile != 0 || _sqlite3OsDeviceCharacteristics(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd)&int32(SQLITE_IOCAP_POWERSAFE_OVERWRITE) != 0 {
|
|
/* Sector size doesn't matter for temporary files. Also, the file
|
|
** may not have been opened yet, in which case the OsSectorSize()
|
|
** call will segfault. */
|
|
(*TPager)(unsafe.Pointer(pPager)).FsectorSize = uint32(512)
|
|
} else {
|
|
(*TPager)(unsafe.Pointer(pPager)).FsectorSize = libc.Uint32FromInt32(_sqlite3SectorSize(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The string z[] is an text representation of a real number.
|
|
// ** Convert this string to a double and write it into *pResult.
|
|
// **
|
|
// ** z[] must be UTF-8 and zero-terminated.
|
|
// **
|
|
// ** Return positive if the result is a valid real number (or integer) and
|
|
// ** zero or negative if the string is empty or contains extraneous text.
|
|
// ** Lower bits of the return value contain addition information about the
|
|
// ** parse:
|
|
// **
|
|
// ** bit 0 => Set if any prefix of the input is valid. Clear if
|
|
// ** there is no prefix of the input that can be seen as
|
|
// ** a valid floating point number.
|
|
// ** bit 1 => Set if the input contains a decimal point or eNNN
|
|
// ** clause. Zero if the input is an integer.
|
|
// ** bit 2 => The input is exactly 0.0, not an underflow from
|
|
// ** some value near zero.
|
|
// ** bit 3 => Set if there are more than about 19 significant
|
|
// ** digits in the input.
|
|
// **
|
|
// ** If the input contains a syntax error but begins with text that might
|
|
// ** be a valid number of some kind, then the result is negative. The
|
|
// ** result is only zero if no prefix of the input could be interpreted as
|
|
// ** a number.
|
|
// **
|
|
// ** Leading and trailing whitespace is ignored. Valid numbers are in
|
|
// ** one of the formats below:
|
|
// **
|
|
// ** [+-]digits[E[+-]digits]
|
|
// ** [+-]digits.[digits][E[+-]digits]
|
|
// ** [+-].digits[E[+-]digits]
|
|
// **
|
|
// ** Algorithm sketch: Compute an unsigned 64-bit integer s and a base-10
|
|
// ** exponent d such that the value encoding by the input is s*pow(10,d).
|
|
// ** Then invoke sqlite3Fp10Convert2() to calculated the closest possible
|
|
// ** IEEE754 double. The sign is added back afterwards, if the input string
|
|
// ** starts with a "-". The use of an unsigned 64-bit s mantissa means that
|
|
// ** only about the first 19 significant digits of the input can contribute
|
|
// ** to the result. This can result in suboptimal rounding decisions when
|
|
// ** correct rounding requires more than 19 input digits. For example,
|
|
// ** this routine renders "3500000000000000.2500001" as
|
|
// ** 3500000000000000.0 instead of 3500000000000000.5 because the decision
|
|
// ** to round up instead of using banker's rounding to round down is determined
|
|
// ** by the 23rd significant digit, which this routine ignores. It is not
|
|
// ** possible to do better without some kind of BigNum.
|
|
// */
|
|
func _sqlite3AtoF(tls *libc.TLS, zIn uintptr, pResult uintptr) (r int32) {
|
|
var d, esign, exp, mState, neg int32
|
|
var s Tu64
|
|
var v, v3, v4 uint32
|
|
var z, v7 uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = d, esign, exp, mState, neg, s, v, z, v3, v4, v7
|
|
z = zIn
|
|
neg = 0 /* True for a negative value */
|
|
s = uint64(0) /* mantissa */
|
|
d = 0 /* Value is s * pow(10,d) */
|
|
mState = 0 /* Value of a single digit */
|
|
goto start_of_text
|
|
start_of_text:
|
|
;
|
|
v3 = uint32(**(**uint8)(__ccgo_up(z))) - libc.Uint32FromUint8('0')
|
|
v = v3
|
|
if !(v3 < uint32(10)) {
|
|
goto _1
|
|
}
|
|
goto parse_integer_part
|
|
parse_integer_part:
|
|
;
|
|
mState = int32(1)
|
|
s = uint64(v)
|
|
z = z + 1
|
|
for {
|
|
v3 = uint32(**(**uint8)(__ccgo_up(z))) - libc.Uint32FromUint8('0')
|
|
v = v3
|
|
if !(v3 < uint32(10)) {
|
|
break
|
|
}
|
|
s = s*uint64(10) + uint64(v)
|
|
z = z + 1
|
|
if s >= (libc.Uint64FromUint32(0xffffffff)|libc.Uint64FromUint32(0xffffffff)<<libc.Int32FromInt32(32)-libc.Uint64FromInt32(9))/libc.Uint64FromInt32(10) {
|
|
mState = int32(9)
|
|
for libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z))])&int32(0x04) != 0 {
|
|
z = z + 1
|
|
d = d + 1
|
|
}
|
|
break
|
|
}
|
|
}
|
|
goto _2
|
|
_1:
|
|
;
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('-') {
|
|
neg = int32(1)
|
|
z = z + 1
|
|
v3 = uint32(**(**uint8)(__ccgo_up(z))) - libc.Uint32FromUint8('0')
|
|
v = v3
|
|
if v3 < uint32(10) {
|
|
goto parse_integer_part
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('+') {
|
|
z = z + 1
|
|
v3 = uint32(**(**uint8)(__ccgo_up(z))) - libc.Uint32FromUint8('0')
|
|
v = v3
|
|
if v3 < uint32(10) {
|
|
goto parse_integer_part
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z))])&int32(0x01) != 0 {
|
|
for cond := true; cond; cond = libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z))])&int32(0x01) != 0 {
|
|
z = z + 1
|
|
}
|
|
goto start_of_text
|
|
} else {
|
|
s = uint64(0)
|
|
}
|
|
}
|
|
}
|
|
_2:
|
|
;
|
|
/* if decimal point is present */
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('.') {
|
|
z = z + 1
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z))])&int32(0x04) != 0 {
|
|
mState = mState | int32(1)
|
|
for {
|
|
if s < (libc.Uint64FromUint32(0xffffffff)|libc.Uint64FromUint32(0xffffffff)<<libc.Int32FromInt32(32)-libc.Uint64FromInt32(9))/libc.Uint64FromInt32(10) {
|
|
s = s*uint64(10) + uint64(**(**uint8)(__ccgo_up(z))) - uint64('0')
|
|
d = d - 1
|
|
} else {
|
|
mState = int32(11)
|
|
}
|
|
goto _8
|
|
_8:
|
|
;
|
|
z = z + 1
|
|
v7 = z
|
|
if !(libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(v7))])&int32(0x04) != 0) {
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
if mState == 0 {
|
|
**(**float64)(__ccgo_up(pResult)) = float64(0)
|
|
return 0
|
|
}
|
|
}
|
|
mState = mState | int32(2)
|
|
} else {
|
|
if mState == 0 {
|
|
**(**float64)(__ccgo_up(pResult)) = float64(0)
|
|
return 0
|
|
}
|
|
}
|
|
/* if exponent is present */
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('e') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('E') {
|
|
z = z + 1
|
|
/* get sign of exponent */
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('-') {
|
|
esign = -int32(1)
|
|
z = z + 1
|
|
} else {
|
|
esign = +libc.Int32FromInt32(1)
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('+') {
|
|
z = z + 1
|
|
}
|
|
}
|
|
/* copy digits to exponent */
|
|
v3 = uint32(**(**uint8)(__ccgo_up(z))) - libc.Uint32FromUint8('0')
|
|
v = v3
|
|
if v3 < uint32(10) {
|
|
exp = libc.Int32FromUint32(v)
|
|
z = z + 1
|
|
mState = mState | int32(2)
|
|
for {
|
|
v3 = uint32(**(**uint8)(__ccgo_up(z))) - libc.Uint32FromUint8('0')
|
|
v = v3
|
|
if !(v3 < uint32(10)) {
|
|
break
|
|
}
|
|
if exp < int32(10000) {
|
|
v4 = libc.Uint32FromInt32(exp*int32(10)) + v
|
|
} else {
|
|
v4 = uint32(10000)
|
|
}
|
|
exp = libc.Int32FromUint32(v4)
|
|
z = z + 1
|
|
}
|
|
d = d + esign*exp
|
|
} else {
|
|
z = z - 1 /* Leave z[0] at 'e' or '+' or '-',
|
|
** so that the return is 0 or -1 */
|
|
}
|
|
}
|
|
/* Convert s*pow(10,d) into real */
|
|
if s == uint64(0) {
|
|
**(**float64)(__ccgo_up(pResult)) = float64(0)
|
|
mState = mState | int32(4)
|
|
} else {
|
|
**(**float64)(__ccgo_up(pResult)) = _sqlite3Fp10Convert2(tls, s, d)
|
|
}
|
|
if neg != 0 {
|
|
**(**float64)(__ccgo_up(pResult)) = -**(**float64)(__ccgo_up(pResult))
|
|
}
|
|
/* return true if number and no extra non-whitespace characters after */
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == 0 {
|
|
return mState
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z))])&int32(0x01) != 0 {
|
|
for cond := true; cond; cond = libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z))])&int32(0x01) != 0 {
|
|
z = z + 1
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == 0 {
|
|
return mState
|
|
}
|
|
}
|
|
return libc.Int32FromUint32(uint32(0xfffffff0) | libc.Uint32FromInt32(mState))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine runs an extensive test of the Bitvec code.
|
|
// **
|
|
// ** The input is an array of integers that acts as a program
|
|
// ** to test the Bitvec. The integers are opcodes followed
|
|
// ** by 0, 1, or 3 operands, depending on the opcode. Another
|
|
// ** opcode follows immediately after the last operand.
|
|
// **
|
|
// ** There are opcodes numbered starting with 0. 0 is the
|
|
// ** "halt" opcode and causes the test to end.
|
|
// **
|
|
// ** 0 Halt and return the number of errors
|
|
// ** 1 N S X Set N bits beginning with S and incrementing by X
|
|
// ** 2 N S X Clear N bits beginning with S and incrementing by X
|
|
// ** 3 N Set N randomly chosen bits
|
|
// ** 4 N Clear N randomly chosen bits
|
|
// ** 5 N S X Set N bits from S increment X in array only, not in bitvec
|
|
// ** 6 Invoice sqlite3ShowBitvec() on the Bitvec object so far
|
|
// ** 7 X Show compile-time parameters and the hash of X
|
|
// **
|
|
// ** The opcodes 1 through 4 perform set and clear operations are performed
|
|
// ** on both a Bitvec object and on a linear array of bits obtained from malloc.
|
|
// ** Opcode 5 works on the linear array only, not on the Bitvec.
|
|
// ** Opcode 5 is used to deliberately induce a fault in order to
|
|
// ** confirm that error detection works. Opcodes 6 and greater are
|
|
// ** state output opcodes. Opcodes 6 and greater are no-ops unless
|
|
// ** SQLite has been compiled with SQLITE_DEBUG.
|
|
// **
|
|
// ** At the conclusion of the test the linear array is compared
|
|
// ** against the Bitvec object. If there are any differences,
|
|
// ** an error is returned. If they are the same, zero is returned.
|
|
// **
|
|
// ** If a memory allocation error occurs, return -1.
|
|
// **
|
|
// ** sz is the size of the Bitvec. Or if sz is negative, make the size
|
|
// ** 2*(unsigned)(-sz) and disabled the linear vector check.
|
|
// */
|
|
func _sqlite3BitvecBuiltinTest(tls *libc.TLS, sz int32, aOp uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var nx, op, pc, rc, v1 int32
|
|
var pBitvec, pTmpSpace, pV, v4 uintptr
|
|
var _ /* i at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _, _ = nx, op, pBitvec, pTmpSpace, pV, pc, rc, v1, v4
|
|
pBitvec = uintptr(0)
|
|
pV = uintptr(0)
|
|
rc = -int32(1)
|
|
/* Allocate the Bitvec to be tested and a linear array of
|
|
** bits to act as the reference */
|
|
if sz <= 0 {
|
|
pBitvec = _sqlite3BitvecCreate(tls, uint32(2)*libc.Uint32FromInt32(-sz))
|
|
pV = uintptr(0)
|
|
} else {
|
|
pBitvec = _sqlite3BitvecCreate(tls, libc.Uint32FromInt32(sz))
|
|
pV = _sqlite3MallocZero(tls, libc.Uint64FromInt64((int64(7)+int64(sz))/int64(8)+int64(1)))
|
|
}
|
|
pTmpSpace = Xsqlite3_malloc64(tls, uint64(BITVEC_SZ))
|
|
if pBitvec == uintptr(0) || pTmpSpace == uintptr(0) || pV == uintptr(0) && sz > 0 {
|
|
goto bitvec_end
|
|
}
|
|
/* NULL pBitvec tests */
|
|
_sqlite3BitvecSet(tls, uintptr(0), uint32(1))
|
|
_sqlite3BitvecClear(tls, uintptr(0), uint32(1), pTmpSpace)
|
|
/* Run the program */
|
|
v1 = libc.Int32FromInt32(0)
|
|
**(**int32)(__ccgo_up(bp)) = v1
|
|
pc = v1
|
|
for {
|
|
v1 = **(**int32)(__ccgo_up(aOp + uintptr(pc)*4))
|
|
op = v1
|
|
if !(v1 != 0) {
|
|
break
|
|
}
|
|
if op >= int32(6) {
|
|
pc = pc + 1
|
|
continue
|
|
}
|
|
switch op {
|
|
case int32(1):
|
|
fallthrough
|
|
case int32(2):
|
|
fallthrough
|
|
case int32(5):
|
|
nx = int32(4)
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(aOp + uintptr(pc+int32(2))*4)) - int32(1)
|
|
**(**int32)(__ccgo_up(aOp + uintptr(pc+int32(2))*4)) += **(**int32)(__ccgo_up(aOp + uintptr(pc+int32(3))*4))
|
|
case int32(3):
|
|
fallthrough
|
|
case int32(4):
|
|
fallthrough
|
|
default:
|
|
nx = int32(2)
|
|
Xsqlite3_randomness(tls, int32(4), bp)
|
|
break
|
|
}
|
|
v4 = aOp + uintptr(pc+int32(1))*4
|
|
*(*int32)(unsafe.Pointer(v4)) = *(*int32)(unsafe.Pointer(v4)) - 1
|
|
v1 = *(*int32)(unsafe.Pointer(v4))
|
|
if v1 > 0 {
|
|
nx = 0
|
|
}
|
|
pc = pc + nx
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) & int32(0x7fffffff) % sz
|
|
if op&int32(1) != 0 {
|
|
if pV != 0 {
|
|
v4 = pV + uintptr((**(**int32)(__ccgo_up(bp))+int32(1))>>int32(3))
|
|
*(*uint8)(unsafe.Pointer(v4)) = uint8(int32(*(*uint8)(unsafe.Pointer(v4))) | libc.Int32FromInt32(1)<<((**(**int32)(__ccgo_up(bp))+libc.Int32FromInt32(1))&libc.Int32FromInt32(7)))
|
|
}
|
|
if op != int32(5) {
|
|
if _sqlite3BitvecSet(tls, pBitvec, libc.Uint32FromInt32(**(**int32)(__ccgo_up(bp))+int32(1))) != 0 {
|
|
goto bitvec_end
|
|
}
|
|
}
|
|
} else {
|
|
if pV != 0 {
|
|
v4 = pV + uintptr((**(**int32)(__ccgo_up(bp))+int32(1))>>int32(3))
|
|
*(*uint8)(unsafe.Pointer(v4)) = uint8(int32(*(*uint8)(unsafe.Pointer(v4))) & ^libc.Int32FromUint8(libc.Uint8FromInt32(libc.Int32FromInt32(1)<<((**(**int32)(__ccgo_up(bp))+libc.Int32FromInt32(1))&libc.Int32FromInt32(7)))))
|
|
}
|
|
_sqlite3BitvecClear(tls, pBitvec, libc.Uint32FromInt32(**(**int32)(__ccgo_up(bp))+int32(1)), pTmpSpace)
|
|
}
|
|
}
|
|
/* Test to make sure the linear array exactly matches the
|
|
** Bitvec object. Start with the assumption that they do
|
|
** match (rc==0). Change rc to non-zero if a discrepancy
|
|
** is found.
|
|
*/
|
|
if pV != 0 {
|
|
rc = libc.Int32FromUint32(libc.Uint32FromInt32(_sqlite3BitvecTest(tls, uintptr(0), uint32(0))+_sqlite3BitvecTest(tls, pBitvec, libc.Uint32FromInt32(sz+int32(1)))+_sqlite3BitvecTest(tls, pBitvec, uint32(0))) + (_sqlite3BitvecSize(tls, pBitvec) - libc.Uint32FromInt32(sz)))
|
|
**(**int32)(__ccgo_up(bp)) = int32(1)
|
|
for {
|
|
if !(**(**int32)(__ccgo_up(bp)) <= sz) {
|
|
break
|
|
}
|
|
if libc.BoolInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(pV + uintptr(**(**int32)(__ccgo_up(bp))>>int32(3)))))&(int32(1)<<(**(**int32)(__ccgo_up(bp))&int32(7))) != 0) != _sqlite3BitvecTest(tls, pBitvec, libc.Uint32FromInt32(**(**int32)(__ccgo_up(bp)))) {
|
|
rc = **(**int32)(__ccgo_up(bp))
|
|
break
|
|
}
|
|
goto _7
|
|
_7:
|
|
;
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) + 1
|
|
}
|
|
} else {
|
|
rc = 0
|
|
}
|
|
/* Free allocated structure */
|
|
goto bitvec_end
|
|
bitvec_end:
|
|
;
|
|
Xsqlite3_free(tls, pTmpSpace)
|
|
Xsqlite3_free(tls, pV)
|
|
_sqlite3BitvecDestroy(tls, pBitvec)
|
|
return rc
|
|
}
|
|
|
|
/********************************** Test and Debug Logic **********************/
|
|
/*
|
|
** Debug tracing macros. Enable by by changing the "0" to "1" and
|
|
** recompiling.
|
|
**
|
|
** When sqlite3PcacheTrace is 1, single line trace messages are issued.
|
|
** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
|
|
** is displayed for many operations, resulting in a lot of output.
|
|
*/
|
|
|
|
/*
|
|
** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
|
|
** This routine runs inside of assert() statements only.
|
|
*/
|
|
|
|
/*
|
|
** Check invariants on a PgHdr entry. Return true if everything is OK.
|
|
** Return false if any invariant is violated.
|
|
**
|
|
** This routine is for use inside of assert() statements only. For
|
|
** example:
|
|
**
|
|
** assert( sqlite3PcachePageSanity(pPg) );
|
|
*/
|
|
|
|
/********************************** Linked List Management ********************/
|
|
|
|
/* Allowed values for second argument to pcacheManageDirtyList() */
|
|
|
|
func _sqlite3BtreeBeginTrans(tls *libc.TLS, p uintptr, wrflag int32, pSchemaVersion uintptr) (r int32) {
|
|
var pBt uintptr
|
|
_ = pBt
|
|
if (*TBtree)(unsafe.Pointer(p)).Fsharable != 0 || libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == TRANS_NONE || libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == int32(TRANS_READ) && wrflag != 0 {
|
|
return _btreeBeginTrans(tls, p, wrflag, pSchemaVersion)
|
|
}
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
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.
|
|
*/
|
|
return _sqlite3PagerOpenSavepoint(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, (*Tsqlite3)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).Fdb)).FnSavepoint)
|
|
} else {
|
|
return SQLITE_OK
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Run a checkpoint on the Btree passed as the first argument.
|
|
// **
|
|
// ** Return SQLITE_LOCKED if this or any other connection has an open
|
|
// ** transaction on the shared-cache the argument Btree is connected to.
|
|
// **
|
|
// ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
|
|
// */
|
|
func _sqlite3BtreeCheckpoint(tls *libc.TLS, p uintptr, eMode int32, pnLog uintptr, pnCkpt uintptr) (r int32) {
|
|
var pBt uintptr
|
|
var rc int32
|
|
_, _ = pBt, rc
|
|
rc = SQLITE_OK
|
|
if p != 0 {
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
_sqlite3BtreeEnter(tls, p)
|
|
if libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FinTransaction) != TRANS_NONE {
|
|
rc = int32(SQLITE_LOCKED)
|
|
} else {
|
|
rc = _sqlite3PagerCheckpoint(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, (*TBtree)(unsafe.Pointer(p)).Fdb, eMode, pnLog, pnCkpt)
|
|
}
|
|
_sqlite3BtreeLeave(tls, p)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If no transaction is active and the database is not a temp-db, clear
|
|
// ** the in-memory pager cache.
|
|
// */
|
|
func _sqlite3BtreeClearCache(tls *libc.TLS, p uintptr) {
|
|
var pBt uintptr
|
|
_ = pBt
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
if libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FinTransaction) == TRANS_NONE {
|
|
_sqlite3PagerClearCache(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete all information from a single table in the database. iTable is
|
|
// ** the page number of the root of the table. After this routine returns,
|
|
// ** the root page is empty, but still exists.
|
|
// **
|
|
// ** This routine will fail with SQLITE_LOCKED if there are any open
|
|
// ** read cursors on the table. Open write cursors are moved to the
|
|
// ** root of the table.
|
|
// **
|
|
// ** If pnChange is not NULL, then the integer value pointed to by pnChange
|
|
// ** is incremented by the number of entries in the table.
|
|
// */
|
|
func _sqlite3BtreeClearTable(tls *libc.TLS, p uintptr, iTable int32, pnChange uintptr) (r int32) {
|
|
var pBt uintptr
|
|
var rc int32
|
|
_, _ = pBt, rc
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
_sqlite3BtreeEnter(tls, p)
|
|
rc = _saveAllCursors(tls, pBt, libc.Uint32FromInt32(iTable), uintptr(0))
|
|
if SQLITE_OK == rc {
|
|
/* Invalidate all incrblob cursors open on table iTable (assuming iTable
|
|
** is the root of a table b-tree - if it is not, the following call is
|
|
** a no-op). */
|
|
if (*TBtree)(unsafe.Pointer(p)).FhasIncrblobCur != 0 {
|
|
_invalidateIncrblobCursors(tls, p, libc.Uint32FromInt32(iTable), 0, int32(1))
|
|
}
|
|
rc = _clearDatabasePage(tls, pBt, libc.Uint32FromInt32(iTable), 0, pnChange)
|
|
}
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete all information from the single table that pCur is open on.
|
|
// **
|
|
// ** This routine only work for pCur on an ephemeral table.
|
|
// */
|
|
func _sqlite3BtreeClearTableOfCursor(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
return _sqlite3BtreeClearTable(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpBtree, libc.Int32FromUint32((*TBtCursor)(unsafe.Pointer(pCur)).FpgnoRoot), uintptr(0))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close a cursor. The read lock on the database file is released
|
|
// ** when the last cursor is closed.
|
|
// */
|
|
func _sqlite3BtreeCloseCursor(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
var pBt, pBtree, pPrev uintptr
|
|
_, _, _ = pBt, pBtree, pPrev
|
|
pBtree = (*TBtCursor)(unsafe.Pointer(pCur)).FpBtree
|
|
if pBtree != 0 {
|
|
pBt = (*TBtCursor)(unsafe.Pointer(pCur)).FpBt
|
|
_sqlite3BtreeEnter(tls, pBtree)
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FpCursor == pCur {
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FpCursor = (*TBtCursor)(unsafe.Pointer(pCur)).FpNext
|
|
} else {
|
|
pPrev = (*TBtShared)(unsafe.Pointer(pBt)).FpCursor
|
|
for cond := true; cond; cond = pPrev != 0 {
|
|
if (*TBtCursor)(unsafe.Pointer(pPrev)).FpNext == pCur {
|
|
(*TBtCursor)(unsafe.Pointer(pPrev)).FpNext = (*TBtCursor)(unsafe.Pointer(pCur)).FpNext
|
|
break
|
|
}
|
|
pPrev = (*TBtCursor)(unsafe.Pointer(pPrev)).FpNext
|
|
}
|
|
}
|
|
_btreeReleaseAllCursorPages(tls, pCur)
|
|
_unlockBtreeIfUnused(tls, pBt)
|
|
Xsqlite3_free(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FaOverflow)
|
|
Xsqlite3_free(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpKey)
|
|
if libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FopenFlags)&int32(BTREE_SINGLE) != 0 && (*TBtShared)(unsafe.Pointer(pBt)).FpCursor == uintptr(0) {
|
|
/* Since the BtShared is not sharable, there is no need to
|
|
** worry about the missing sqlite3BtreeLeave() call here. */
|
|
_sqlite3BtreeClose(tls, pBtree)
|
|
} else {
|
|
_sqlite3BtreeLeave(tls, pBtree)
|
|
}
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FpBtree = uintptr(0)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine does the first phase of a two-phase commit. This routine
|
|
// ** causes a rollback journal to be created (if it does not already exist)
|
|
// ** and populated with enough information so that if a power loss occurs
|
|
// ** the database can be restored to its original state by playing back
|
|
// ** the journal. Then the contents of the journal are flushed out to
|
|
// ** the disk. After the journal is safely on oxide, the changes to the
|
|
// ** database are written into the database file and flushed to oxide.
|
|
// ** At the end of this call, the rollback journal still exists on the
|
|
// ** disk and we are still holding all locks, so the transaction has not
|
|
// ** committed. See sqlite3BtreeCommitPhaseTwo() for the second phase of the
|
|
// ** commit process.
|
|
// **
|
|
// ** This call is a no-op if no write-transaction is currently active on pBt.
|
|
// **
|
|
// ** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to
|
|
// ** the name of a super-journal file that should be written into the
|
|
// ** individual journal file, or is NULL, indicating no super-journal file
|
|
// ** (single database transaction).
|
|
// **
|
|
// ** When this is called, the super-journal should already have been
|
|
// ** created, populated with this journal pointer and synced to disk.
|
|
// **
|
|
// ** Once this is routine has returned, the only thing required to commit
|
|
// ** the write-transaction for this database file is to delete the journal.
|
|
// */
|
|
func _sqlite3BtreeCommitPhaseOne(tls *libc.TLS, p uintptr, zSuperJrnl uintptr) (r int32) {
|
|
var pBt uintptr
|
|
var rc int32
|
|
_, _ = pBt, rc
|
|
rc = SQLITE_OK
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == int32(TRANS_WRITE) {
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
_sqlite3BtreeEnter(tls, p)
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum != 0 {
|
|
rc = _autoVacuumCommit(tls, p)
|
|
if rc != SQLITE_OK {
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return rc
|
|
}
|
|
}
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FbDoTruncate != 0 {
|
|
_sqlite3PagerTruncateImage(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, (*TBtShared)(unsafe.Pointer(pBt)).FnPage)
|
|
}
|
|
rc = _sqlite3PagerCommitPhaseOne(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, zSuperJrnl, 0)
|
|
_sqlite3BtreeLeave(tls, p)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Commit the transaction currently in progress.
|
|
// **
|
|
// ** This routine implements the second phase of a 2-phase commit. The
|
|
// ** sqlite3BtreeCommitPhaseOne() routine does the first phase and should
|
|
// ** be invoked prior to calling this routine. The sqlite3BtreeCommitPhaseOne()
|
|
// ** routine did all the work of writing information out to disk and flushing the
|
|
// ** contents so that they are written onto the disk platter. All this
|
|
// ** routine has to do is delete or truncate or zero the header in the
|
|
// ** the rollback journal (which causes the transaction to commit) and
|
|
// ** drop locks.
|
|
// **
|
|
// ** Normally, if an error occurs while the pager layer is attempting to
|
|
// ** finalize the underlying journal file, this function returns an error and
|
|
// ** the upper layer will attempt a rollback. However, if the second argument
|
|
// ** is non-zero then this b-tree transaction is part of a multi-file
|
|
// ** transaction. In this case, the transaction has already been committed
|
|
// ** (by deleting a super-journal file) and the caller will ignore this
|
|
// ** functions return code. So, even if an error occurs in the pager layer,
|
|
// ** reset the b-tree objects internal state to indicate that the write
|
|
// ** transaction has been closed. This is quite safe, as the pager will have
|
|
// ** transitioned to the error state.
|
|
// **
|
|
// ** This will release the write lock on the database file. If there
|
|
// ** are no active cursors, it also releases the read lock.
|
|
// */
|
|
func _sqlite3BtreeCommitPhaseTwo(tls *libc.TLS, p uintptr, bCleanup int32) (r int32) {
|
|
var pBt uintptr
|
|
var rc int32
|
|
_, _ = pBt, rc
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == TRANS_NONE {
|
|
return SQLITE_OK
|
|
}
|
|
_sqlite3BtreeEnter(tls, p)
|
|
/* If the handle has a write-transaction open, commit the shared-btrees
|
|
** transaction and set the shared state to TRANS_READ.
|
|
*/
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == int32(TRANS_WRITE) {
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
rc = _sqlite3PagerCommitPhaseTwo(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager)
|
|
if rc != SQLITE_OK && bCleanup == 0 {
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return rc
|
|
}
|
|
(*TBtree)(unsafe.Pointer(p)).FiBDataVersion = (*TBtree)(unsafe.Pointer(p)).FiBDataVersion - 1 /* Compensate for pPager->iDataVersion++; */
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FinTransaction = uint8(TRANS_READ)
|
|
_btreeClearHasContent(tls, pBt)
|
|
}
|
|
_btreeEndTransaction(tls, p)
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Determine whether or not a cursor has moved from the position where
|
|
// ** it was last placed, or has been invalidated for any other reason.
|
|
// ** Cursors can move when the row they are pointing at is deleted out
|
|
// ** from under them, for example. Cursor might also move if a btree
|
|
// ** is rebalanced.
|
|
// **
|
|
// ** Calling this routine with a NULL cursor pointer returns false.
|
|
// **
|
|
// ** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor
|
|
// ** back to where it ought to be if this routine returns true.
|
|
// */
|
|
func _sqlite3BtreeCursorHasMoved(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
return libc.BoolInt32(CURSOR_VALID != libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pCur))))
|
|
}
|
|
|
|
func _sqlite3BtreeCursorIsValidNN(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
return libc.BoolInt32(libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == CURSOR_VALID)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine restores a cursor back to its original position after it
|
|
// ** has been moved by some outside activity (such as a btree rebalance or
|
|
// ** a row having been deleted out from under the cursor).
|
|
// **
|
|
// ** On success, the *pDifferentRow parameter is false if the cursor is left
|
|
// ** pointing at exactly the same row. *pDifferntRow is the row the cursor
|
|
// ** was pointing to has been deleted, forcing the cursor to point to some
|
|
// ** nearby row.
|
|
// **
|
|
// ** This routine should only be called for a cursor that just returned
|
|
// ** TRUE from sqlite3BtreeCursorHasMoved().
|
|
// */
|
|
func _sqlite3BtreeCursorRestore(tls *libc.TLS, pCur uintptr, pDifferentRow uintptr) (r int32) {
|
|
var rc, v1 int32
|
|
_, _ = rc, v1
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) >= int32(CURSOR_REQUIRESEEK) {
|
|
v1 = _btreeRestoreCursorPosition(tls, pCur)
|
|
} else {
|
|
v1 = SQLITE_OK
|
|
}
|
|
rc = v1
|
|
if rc != 0 {
|
|
**(**int32)(__ccgo_up(pDifferentRow)) = int32(1)
|
|
return rc
|
|
}
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) != CURSOR_VALID {
|
|
**(**int32)(__ccgo_up(pDifferentRow)) = int32(1)
|
|
} else {
|
|
**(**int32)(__ccgo_up(pDifferentRow)) = 0
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
func _sqlite3BtreeDropTable(tls *libc.TLS, p uintptr, iTable int32, piMoved uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
_sqlite3BtreeEnter(tls, p)
|
|
rc = _btreeDropTable(tls, p, libc.Uint32FromInt32(iTable), piMoved)
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return rc
|
|
}
|
|
|
|
func _sqlite3BtreeEnterAll(tls *libc.TLS, db uintptr) {
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FnoSharedCache) == 0 {
|
|
_btreeEnterAll(tls, db)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return TRUE if the cursor is not pointing at an entry of the table.
|
|
// **
|
|
// ** TRUE will be returned after a call to sqlite3BtreeNext() moves
|
|
// ** past the last entry in the table or sqlite3BtreePrev() moves past
|
|
// ** the first entry. TRUE is also returned if the table is empty.
|
|
// */
|
|
func _sqlite3BtreeEof(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
/* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries
|
|
** have been deleted? This API will need to change to return an error code
|
|
** as well as the boolean result value.
|
|
*/
|
|
return libc.BoolInt32(CURSOR_VALID != libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the currently defined page size
|
|
// */
|
|
func _sqlite3BtreeGetPageSize(tls *libc.TLS, p uintptr) (r int32) {
|
|
return libc.Int32FromUint32((*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FpageSize)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the number of bytes of space at the end of every page that
|
|
// ** are intentionally left unused. This is the "reserved" space that is
|
|
// ** sometimes used by extensions.
|
|
// **
|
|
// ** The value returned is the larger of the current reserve size and
|
|
// ** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
|
|
// ** The amount of reserve can only grow - never shrink.
|
|
// */
|
|
func _sqlite3BtreeGetRequestedReserve(tls *libc.TLS, p uintptr) (r int32) {
|
|
var n1, n2, v1 int32
|
|
_, _, _ = n1, n2, v1
|
|
_sqlite3BtreeEnter(tls, p)
|
|
n1 = libc.Int32FromUint8((*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FnReserveWanted)
|
|
n2 = _sqlite3BtreeGetReserveNoMutex(tls, p)
|
|
_sqlite3BtreeLeave(tls, p)
|
|
if n1 > n2 {
|
|
v1 = n1
|
|
} else {
|
|
v1 = n2
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is similar to sqlite3BtreeGetReserve(), except that it
|
|
// ** may only be called if it is guaranteed that the b-tree mutex is already
|
|
// ** held.
|
|
// **
|
|
// ** This is useful in one special case in the backup API code where it is
|
|
// ** known that the shared b-tree mutex is held, but the mutex on the
|
|
// ** database handle that owns *p is not. In this case if sqlite3BtreeEnter()
|
|
// ** were to be called, it might collide with some other operation on the
|
|
// ** database handle that owns *p, causing undefined behavior.
|
|
// */
|
|
func _sqlite3BtreeGetReserveNoMutex(tls *libc.TLS, p uintptr) (r int32) {
|
|
var n int32
|
|
_ = n
|
|
n = libc.Int32FromUint32((*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FpageSize - (*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FusableSize)
|
|
return n
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Set *pRes to 1 (true) if the BTree pointed to by cursor pCur contains zero
|
|
// ** rows of content. Set *pRes to 0 (false) if the table contains content.
|
|
// ** Return SQLITE_OK on success or some error code (ex: SQLITE_NOMEM) if
|
|
// ** something goes wrong.
|
|
// */
|
|
func _sqlite3BtreeIsEmpty(tls *libc.TLS, pCur uintptr, pRes uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == CURSOR_VALID {
|
|
**(**int32)(__ccgo_up(pRes)) = 0
|
|
return SQLITE_OK
|
|
}
|
|
rc = _moveToRoot(tls, pCur)
|
|
if rc == int32(SQLITE_EMPTY) {
|
|
**(**int32)(__ccgo_up(pRes)) = int32(1)
|
|
rc = SQLITE_OK
|
|
} else {
|
|
**(**int32)(__ccgo_up(pRes)) = 0
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the given Btree is read-only.
|
|
// */
|
|
func _sqlite3BtreeIsReadonly(tls *libc.TLS, p uintptr) (r int32) {
|
|
return libc.BoolInt32(libc.Int32FromUint16((*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FbtsFlags)&int32(BTS_READ_ONLY) != 0)
|
|
}
|
|
|
|
func _sqlite3BtreeLast(tls *libc.TLS, pCur uintptr, pRes uintptr) (r int32) {
|
|
/* If the cursor already points to the last entry, this is a no-op. */
|
|
if CURSOR_VALID == libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) && libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FcurFlags)&int32(BTCF_AtLast) != 0 {
|
|
**(**int32)(__ccgo_up(pRes)) = 0
|
|
return SQLITE_OK
|
|
}
|
|
return _btreeLast(tls, pCur, pRes)
|
|
}
|
|
|
|
func _sqlite3BtreeLeaveAll(tls *libc.TLS, db uintptr) {
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FnoSharedCache) == 0 {
|
|
_btreeLeaveAll(tls, db)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Obtain a lock on the table whose root page is iTab. The
|
|
// ** lock is a write lock if isWritelock is true or a read lock
|
|
// ** if it is false.
|
|
// */
|
|
func _sqlite3BtreeLockTable(tls *libc.TLS, p uintptr, iTab int32, isWriteLock Tu8) (r int32) {
|
|
var lockType Tu8
|
|
var rc int32
|
|
_, _ = lockType, rc
|
|
rc = SQLITE_OK
|
|
if (*TBtree)(unsafe.Pointer(p)).Fsharable != 0 {
|
|
lockType = libc.Uint8FromInt32(int32(READ_LOCK) + libc.Int32FromUint8(isWriteLock))
|
|
_sqlite3BtreeEnter(tls, p)
|
|
rc = _querySharedCacheTableLock(tls, p, libc.Uint32FromInt32(iTab), lockType)
|
|
if rc == SQLITE_OK {
|
|
rc = _setSharedCacheTableLock(tls, p, libc.Uint32FromInt32(iTab), lockType)
|
|
}
|
|
_sqlite3BtreeLeave(tls, p)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return an upper bound on the size of any record for the table
|
|
// ** that the cursor is pointing into.
|
|
// **
|
|
// ** This is an optimization. Everything will still work if this
|
|
// ** routine always returns 2147483647 (which is the largest record
|
|
// ** that SQLite can handle) or more. But returning a smaller value might
|
|
// ** prevent large memory allocations when trying to interpret a
|
|
// ** corrupt database.
|
|
// **
|
|
// ** The current implementation merely returns the size of the underlying
|
|
// ** database file.
|
|
// */
|
|
func _sqlite3BtreeMaxRecordSize(tls *libc.TLS, pCur uintptr) (r Tsqlite3_int64) {
|
|
return libc.Int64FromUint32((*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FpageSize) * libc.Int64FromUint32((*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FnPage)
|
|
}
|
|
|
|
func _sqlite3BtreePayloadChecked(tls *libc.TLS, pCur uintptr, offset Tu32, amt Tu32, pBuf uintptr) (r int32) {
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == CURSOR_VALID {
|
|
return _accessPayload(tls, pCur, offset, amt, pBuf, 0)
|
|
} else {
|
|
return _accessPayloadChecked(tls, pCur, offset, amt, pBuf)
|
|
}
|
|
return r
|
|
}
|
|
|
|
func _sqlite3BtreePrevious(tls *libc.TLS, pCur uintptr, flags int32) (r int32) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
_ = flags /* Used in COMDB2 but not native SQLite */
|
|
v1 = pCur + 1
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(BTCF_AtLast) | libc.Int32FromInt32(BTCF_ValidOvfl) | libc.Int32FromInt32(BTCF_ValidNKey)))
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize = uint16(0)
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) != CURSOR_VALID || libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix) == 0 || libc.Int32FromUint8((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).Fleaf) == 0 {
|
|
return _btreePrevious(tls, pCur)
|
|
}
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = (*TBtCursor)(unsafe.Pointer(pCur)).Fix - 1
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Argument pCsr must be a cursor opened for writing on an
|
|
// ** INTKEY table currently pointing at a valid table entry.
|
|
// ** This function modifies the data stored as part of that entry.
|
|
// **
|
|
// ** Only the data content may only be modified, it is not possible to
|
|
// ** change the length of the data stored. If this function is called with
|
|
// ** parameters that attempt to write past the end of the existing data,
|
|
// ** no modifications are made and SQLITE_CORRUPT is returned.
|
|
// */
|
|
func _sqlite3BtreePutData(tls *libc.TLS, pCsr uintptr, offset Tu32, amt Tu32, z uintptr) (r int32) {
|
|
var rc, v1 int32
|
|
_, _ = rc, v1
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCsr)).FeState) >= int32(CURSOR_REQUIRESEEK) {
|
|
v1 = _btreeRestoreCursorPosition(tls, pCsr)
|
|
} else {
|
|
v1 = SQLITE_OK
|
|
}
|
|
rc = v1
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCsr)).FeState) != CURSOR_VALID {
|
|
return int32(SQLITE_ABORT)
|
|
}
|
|
/* Save the positions of all other cursors open on this table. This is
|
|
** required in case any of them are holding references to an xFetch
|
|
** version of the b-tree page modified by the accessPayload call below.
|
|
**
|
|
** Note that pCsr must be open on a INTKEY table and saveCursorPosition()
|
|
** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence
|
|
** saveAllCursors can only return SQLITE_OK.
|
|
*/
|
|
_saveAllCursors(tls, (*TBtCursor)(unsafe.Pointer(pCsr)).FpBt, (*TBtCursor)(unsafe.Pointer(pCsr)).FpgnoRoot, pCsr)
|
|
/* Check some assumptions:
|
|
** (a) the cursor is open for writing,
|
|
** (b) there is a read/write transaction open,
|
|
** (c) the connection holds a write-lock on the table (if required),
|
|
** (d) there are no conflicting read-locks, and
|
|
** (e) the cursor points at a valid row of an intKey table.
|
|
*/
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCsr)).FcurFlags)&int32(BTCF_WriteFlag) == 0 {
|
|
return int32(SQLITE_READONLY)
|
|
}
|
|
return _accessPayload(tls, pCsr, offset, amt, z, int32(1))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Rollback the transaction in progress.
|
|
// **
|
|
// ** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped).
|
|
// ** Only write cursors are tripped if writeOnly is true but all cursors are
|
|
// ** tripped if writeOnly is false. Any attempt to use
|
|
// ** a tripped cursor will result in an error.
|
|
// **
|
|
// ** This will release the write lock on the database file. If there
|
|
// ** are no active cursors, it also releases the read lock.
|
|
// */
|
|
func _sqlite3BtreeRollback(tls *libc.TLS, p uintptr, tripCode int32, writeOnly int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var pBt uintptr
|
|
var rc, rc2, rc21, v1 int32
|
|
var _ /* pPage1 at bp+0 */ uintptr
|
|
_, _, _, _, _ = pBt, rc, rc2, rc21, v1
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
_sqlite3BtreeEnter(tls, p)
|
|
if tripCode == SQLITE_OK {
|
|
v1 = _saveAllCursors(tls, pBt, uint32(0), uintptr(0))
|
|
tripCode = v1
|
|
rc = v1
|
|
if rc != 0 {
|
|
writeOnly = 0
|
|
}
|
|
} else {
|
|
rc = SQLITE_OK
|
|
}
|
|
if tripCode != 0 {
|
|
rc2 = _sqlite3BtreeTripAllCursors(tls, p, tripCode, writeOnly)
|
|
if rc2 != SQLITE_OK {
|
|
rc = rc2
|
|
}
|
|
}
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == int32(TRANS_WRITE) {
|
|
rc21 = _sqlite3PagerRollback(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager)
|
|
if rc21 != SQLITE_OK {
|
|
rc = rc21
|
|
}
|
|
/* The rollback may have destroyed the pPage1->aData value. So
|
|
** call btreeGetPage() on page 1 again to make
|
|
** sure pPage1->aData is set correctly. */
|
|
if _btreeGetPage(tls, pBt, uint32(1), bp, 0) == SQLITE_OK {
|
|
_btreeSetNPage(tls, pBt, **(**uintptr)(__ccgo_up(bp)))
|
|
_releasePageOne(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FinTransaction = uint8(TRANS_READ)
|
|
_btreeClearHasContent(tls, pBt)
|
|
}
|
|
_btreeEndTransaction(tls, p)
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The second argument to this function, op, is always SAVEPOINT_ROLLBACK
|
|
// ** or SAVEPOINT_RELEASE. This function either releases or rolls back the
|
|
// ** savepoint identified by parameter iSavepoint, depending on the value
|
|
// ** of op.
|
|
// **
|
|
// ** Normally, iSavepoint is greater than or equal to zero. However, if op is
|
|
// ** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the
|
|
// ** contents of the entire transaction are rolled back. This is different
|
|
// ** from a normal transaction rollback, as no locks are released and the
|
|
// ** transaction remains open.
|
|
// */
|
|
func _sqlite3BtreeSavepoint(tls *libc.TLS, p uintptr, op int32, iSavepoint int32) (r int32) {
|
|
var pBt uintptr
|
|
var rc int32
|
|
_, _ = pBt, rc
|
|
rc = SQLITE_OK
|
|
if p != 0 && libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == int32(TRANS_WRITE) {
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
_sqlite3BtreeEnter(tls, p)
|
|
if op == int32(SAVEPOINT_ROLLBACK) {
|
|
rc = _saveAllCursors(tls, pBt, uint32(0), uintptr(0))
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3PagerSavepoint(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, op, iSavepoint)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if iSavepoint < 0 && libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_INITIALLY_EMPTY) != 0 {
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FnPage = uint32(0)
|
|
}
|
|
rc = _newDatabase(tls, pBt)
|
|
_btreeSetNPage(tls, pBt, (*TBtShared)(unsafe.Pointer(pBt)).FpPage1)
|
|
/* pBt->nPage might be zero if the database was corrupt when
|
|
** the transaction was started. Otherwise, it must be at least 1. */
|
|
}
|
|
_sqlite3BtreeLeave(tls, p)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function returns a pointer to a blob of memory associated with
|
|
// ** a single shared-btree. The memory is used by client code for its own
|
|
// ** purposes (for example, to store a high-level schema associated with
|
|
// ** the shared-btree). The btree layer manages reference counting issues.
|
|
// **
|
|
// ** The first time this is called on a shared-btree, nBytes bytes of memory
|
|
// ** are allocated, zeroed, and returned to the caller. For each subsequent
|
|
// ** call the nBytes parameter is ignored and a pointer to the same blob
|
|
// ** of memory returned.
|
|
// **
|
|
// ** If the nBytes parameter is 0 and the blob of memory has not yet been
|
|
// ** allocated, a null pointer is returned. If the blob has already been
|
|
// ** allocated, it is returned as normal.
|
|
// **
|
|
// ** Just before the shared-btree is closed, the function passed as the
|
|
// ** xFree argument when the memory allocation was made is invoked on the
|
|
// ** blob of allocated memory. The xFree function should not call sqlite3_free()
|
|
// ** on the memory, the btree layer does that.
|
|
// */
|
|
func _sqlite3BtreeSchema(tls *libc.TLS, p uintptr, nBytes int32, __ccgo_fp_xFree uintptr) (r uintptr) {
|
|
var pBt uintptr
|
|
_ = pBt
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
_sqlite3BtreeEnter(tls, p)
|
|
if !((*TBtShared)(unsafe.Pointer(pBt)).FpSchema != 0) && nBytes != 0 {
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FpSchema = _sqlite3DbMallocZero(tls, uintptr(0), libc.Uint64FromInt32(nBytes))
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FxFreeSchema = __ccgo_fp_xFree
|
|
}
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return (*TBtShared)(unsafe.Pointer(pBt)).FpSchema
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum'
|
|
// ** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it
|
|
// ** is disabled. The default value for the auto-vacuum property is
|
|
// ** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
|
|
// */
|
|
func _sqlite3BtreeSetAutoVacuum(tls *libc.TLS, p uintptr, autoVacuum int32) (r int32) {
|
|
var av Tu8
|
|
var pBt uintptr
|
|
var rc, v1 int32
|
|
var v2 bool
|
|
_, _, _, _, _ = av, pBt, rc, v1, v2
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
rc = SQLITE_OK
|
|
av = libc.Uint8FromInt32(autoVacuum)
|
|
_sqlite3BtreeEnter(tls, p)
|
|
if v2 = libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_PAGESIZE_FIXED) != 0; v2 {
|
|
if av != 0 {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
}
|
|
if v2 && v1 != libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum) {
|
|
rc = int32(SQLITE_READONLY)
|
|
} else {
|
|
if av != 0 {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum = libc.Uint8FromInt32(v1)
|
|
if libc.Int32FromUint8(av) == int32(2) {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FincrVacuum = libc.Uint8FromInt32(v1)
|
|
}
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the Btree passed as the only argument is sharable.
|
|
// */
|
|
func _sqlite3BtreeSharable(tls *libc.TLS, p uintptr) (r int32) {
|
|
return libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).Fsharable)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine sets the state to CURSOR_FAULT and the error
|
|
// ** code to errCode for every cursor on any BtShared that pBtree
|
|
// ** references. Or if the writeOnly flag is set to 1, then only
|
|
// ** trip write cursors and leave read cursors unchanged.
|
|
// **
|
|
// ** Every cursor is a candidate to be tripped, including cursors
|
|
// ** that belong to other database connections that happen to be
|
|
// ** sharing the cache with pBtree.
|
|
// **
|
|
// ** This routine gets called when a rollback occurs. If the writeOnly
|
|
// ** flag is true, then only write-cursors need be tripped - read-only
|
|
// ** cursors save their current positions so that they may continue
|
|
// ** following the rollback. Or, if writeOnly is false, all cursors are
|
|
// ** tripped. In general, writeOnly is false if the transaction being
|
|
// ** rolled back modified the database schema. In this case b-tree root
|
|
// ** pages may be moved or deleted from the database altogether, making
|
|
// ** it unsafe for read cursors to continue.
|
|
// **
|
|
// ** If the writeOnly flag is true and an error is encountered while
|
|
// ** saving the current position of a read-only cursor, all cursors,
|
|
// ** including all read-cursors are tripped.
|
|
// **
|
|
// ** SQLITE_OK is returned if successful, or if an error occurs while
|
|
// ** saving a cursor position, an SQLite error code.
|
|
// */
|
|
func _sqlite3BtreeTripAllCursors(tls *libc.TLS, pBtree uintptr, errCode int32, writeOnly int32) (r int32) {
|
|
var p uintptr
|
|
var rc int32
|
|
_, _ = p, rc
|
|
rc = SQLITE_OK
|
|
if pBtree != 0 {
|
|
_sqlite3BtreeEnter(tls, pBtree)
|
|
p = (*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(pBtree)).FpBt)).FpCursor
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if writeOnly != 0 && libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(p)).FcurFlags)&int32(BTCF_WriteFlag) == 0 {
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(p)).FeState) == CURSOR_VALID || libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(p)).FeState) == int32(CURSOR_SKIPNEXT) {
|
|
rc = _saveCursorPosition(tls, p)
|
|
if rc != SQLITE_OK {
|
|
_sqlite3BtreeTripAllCursors(tls, pBtree, rc, 0)
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
_sqlite3BtreeClearCursor(tls, p)
|
|
(*TBtCursor)(unsafe.Pointer(p)).FeState = uint8(CURSOR_FAULT)
|
|
(*TBtCursor)(unsafe.Pointer(p)).FskipNext = errCode
|
|
}
|
|
_btreeReleaseAllCursorPages(tls, p)
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TBtCursor)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
_sqlite3BtreeLeave(tls, pBtree)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE
|
|
// ** to describe the current transaction state of Btree p.
|
|
// */
|
|
func _sqlite3BtreeTxnState(tls *libc.TLS, p uintptr) (r int32) {
|
|
var v1 int32
|
|
_ = v1
|
|
if p != 0 {
|
|
v1 = libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is called to code the required FOR EACH ROW triggers for an operation
|
|
// ** on table pTab. The operation to code triggers for (INSERT, UPDATE or DELETE)
|
|
// ** is given by the op parameter. The tr_tm parameter determines whether the
|
|
// ** BEFORE or AFTER triggers are coded. If the operation is an UPDATE, then
|
|
// ** parameter pChanges is passed the list of columns being modified.
|
|
// **
|
|
// ** If there are no triggers that fire at the specified time for the specified
|
|
// ** operation on pTab, this function is a no-op.
|
|
// **
|
|
// ** The reg argument is the address of the first in an array of registers
|
|
// ** that contain the values substituted for the new.* and old.* references
|
|
// ** in the trigger program. If N is the number of columns in table pTab
|
|
// ** (a copy of pTab->nCol), then registers are populated as follows:
|
|
// **
|
|
// ** Register Contains
|
|
// ** ------------------------------------------------------
|
|
// ** reg+0 OLD.rowid
|
|
// ** reg+1 OLD.* value of left-most column of pTab
|
|
// ** ... ...
|
|
// ** reg+N OLD.* value of right-most column of pTab
|
|
// ** reg+N+1 NEW.rowid
|
|
// ** reg+N+2 NEW.* value of left-most column of pTab
|
|
// ** ... ...
|
|
// ** reg+N+N+1 NEW.* value of right-most column of pTab
|
|
// **
|
|
// ** For ON DELETE triggers, the registers containing the NEW.* values will
|
|
// ** never be accessed by the trigger program, so they are not allocated or
|
|
// ** populated by the caller (there is no data to populate them with anyway).
|
|
// ** Similarly, for ON INSERT triggers the values stored in the OLD.* registers
|
|
// ** are never accessed, and so are not allocated by the caller. So, for an
|
|
// ** ON INSERT trigger, the value passed to this function as parameter reg
|
|
// ** is not a readable register, although registers (reg+N) through
|
|
// ** (reg+N+N+1) are.
|
|
// **
|
|
// ** Parameter orconf is the default conflict resolution algorithm for the
|
|
// ** trigger program to use (REPLACE, IGNORE etc.). Parameter ignoreJump
|
|
// ** is the instruction that control should jump to if a trigger program
|
|
// ** raises an IGNORE exception.
|
|
// */
|
|
func _sqlite3CodeRowTrigger(tls *libc.TLS, pParse uintptr, pTrigger uintptr, op int32, pChanges uintptr, tr_tm int32, pTab uintptr, reg int32, orconf int32, ignoreJump int32) {
|
|
var p uintptr
|
|
_ = p /* Used to iterate through pTrigger list */
|
|
p = pTrigger
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
/* Sanity checking: The schema for the trigger and for the table are
|
|
** always defined. The trigger must be in the same schema as the table
|
|
** or else it must be a TEMP trigger. */
|
|
/* Determine whether we should code this trigger. One of two choices:
|
|
** 1. The trigger is an exact match to the current DML statement
|
|
** 2. This is a RETURNING trigger for INSERT but we are currently
|
|
** doing the UPDATE part of an UPSERT.
|
|
*/
|
|
if (libc.Int32FromUint8((*TTrigger)(unsafe.Pointer(p)).Fop) == op || (*TTrigger)(unsafe.Pointer(p)).FbReturning != 0 && libc.Int32FromUint8((*TTrigger)(unsafe.Pointer(p)).Fop) == int32(TK_INSERT) && op == int32(TK_UPDATE)) && libc.Int32FromUint8((*TTrigger)(unsafe.Pointer(p)).Ftr_tm) == tr_tm && _checkColumnOverlap(tls, (*TTrigger)(unsafe.Pointer(p)).FpColumns, pChanges) != 0 {
|
|
if !((*TTrigger)(unsafe.Pointer(p)).FbReturning != 0) {
|
|
_sqlite3CodeRowTriggerDirect(tls, pParse, p, pTab, reg, orconf, ignoreJump)
|
|
} else {
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel == uintptr(0) {
|
|
_codeReturningTrigger(tls, pParse, p, pTab, reg)
|
|
}
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TTrigger)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a new expression node from a zero-terminated token that has
|
|
// ** already been dequoted.
|
|
// */
|
|
func _sqlite3Expr(tls *libc.TLS, db uintptr, op int32, zToken uintptr) (r uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var _ /* x at bp+0 */ TToken
|
|
(**(**TToken)(__ccgo_up(bp))).Fz = zToken
|
|
(**(**TToken)(__ccgo_up(bp))).Fn = libc.Uint32FromInt32(_sqlite3Strlen30(tls, zToken))
|
|
return _sqlite3ExprAlloc(tls, db, op, bp, 0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the collating sequence for expression pExpr to be the collating
|
|
// ** sequence named by pToken. Return a pointer to a new Expr node that
|
|
// ** implements the COLLATE operator.
|
|
// **
|
|
// ** If a memory allocation error occurs, that fact is recorded in pParse->db
|
|
// ** and the pExpr parameter is returned unchanged.
|
|
// */
|
|
func _sqlite3ExprAddCollateToken(tls *libc.TLS, pParse uintptr, pExpr uintptr, pCollName uintptr, dequote int32) (r uintptr) {
|
|
var pNew uintptr
|
|
_ = pNew
|
|
if (*TToken)(unsafe.Pointer(pCollName)).Fn > uint32(0) {
|
|
pNew = _sqlite3ExprAlloc(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, int32(TK_COLLATE), pCollName, dequote)
|
|
if pNew != 0 {
|
|
(*TExpr)(unsafe.Pointer(pNew)).FpLeft = pExpr
|
|
**(**Tu32)(__ccgo_up(pNew + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_Collate) | libc.Int32FromInt32(EP_Skip))
|
|
pExpr = pNew
|
|
}
|
|
}
|
|
return pExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Join two expressions using an AND operator. If either expression is
|
|
// ** NULL, then just return the other expression.
|
|
// **
|
|
// ** If one side or the other of the AND is known to be false, and neither side
|
|
// ** is part of an ON clause, then instead of returning an AND expression,
|
|
// ** just return a constant expression with a value of false.
|
|
// */
|
|
func _sqlite3ExprAnd(tls *libc.TLS, pParse uintptr, pLeft uintptr, pRight uintptr) (r uintptr) {
|
|
var db uintptr
|
|
var f Tu32
|
|
_, _ = db, f
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if pLeft == uintptr(0) {
|
|
return pRight
|
|
} else {
|
|
if pRight == uintptr(0) {
|
|
return pLeft
|
|
} else {
|
|
f = (*TExpr)(unsafe.Pointer(pLeft)).Fflags | (*TExpr)(unsafe.Pointer(pRight)).Fflags
|
|
if f&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_InnerON)|libc.Int32FromInt32(EP_IsFalse)|libc.Int32FromInt32(EP_HasFunc)) == uint32(EP_IsFalse) && !(libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= libc.Int32FromInt32(PARSE_MODE_RENAME)) {
|
|
_sqlite3ExprDeferredDelete(tls, pParse, pLeft)
|
|
_sqlite3ExprDeferredDelete(tls, pParse, pRight)
|
|
return _sqlite3ExprInt32(tls, db, 0)
|
|
} else {
|
|
return _sqlite3PExpr(tls, pParse, int32(TK_AND), pLeft, pRight)
|
|
}
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Attach subtrees pLeft and pRight to the Expr node pRoot.
|
|
// **
|
|
// ** If pRoot==NULL that means that a memory allocation error has occurred.
|
|
// ** In that case, delete the subtrees pLeft and pRight.
|
|
// */
|
|
func _sqlite3ExprAttachSubtrees(tls *libc.TLS, db uintptr, pRoot uintptr, pLeft uintptr, pRight uintptr) {
|
|
if pRoot == uintptr(0) {
|
|
_sqlite3ExprDelete(tls, db, pLeft)
|
|
_sqlite3ExprDelete(tls, db, pRight)
|
|
} else {
|
|
if pRight != 0 {
|
|
(*TExpr)(unsafe.Pointer(pRoot)).FpRight = pRight
|
|
**(**Tu32)(__ccgo_up(pRoot + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_Collate)|libc.Int32FromInt32(EP_Subquery)|libc.Int32FromInt32(EP_HasFunc)) & (*TExpr)(unsafe.Pointer(pRight)).Fflags
|
|
(*TExpr)(unsafe.Pointer(pRoot)).FnHeight = (*TExpr)(unsafe.Pointer(pRight)).FnHeight + int32(1)
|
|
} else {
|
|
(*TExpr)(unsafe.Pointer(pRoot)).FnHeight = int32(1)
|
|
}
|
|
if pLeft != 0 {
|
|
(*TExpr)(unsafe.Pointer(pRoot)).FpLeft = pLeft
|
|
**(**Tu32)(__ccgo_up(pRoot + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_Collate)|libc.Int32FromInt32(EP_Subquery)|libc.Int32FromInt32(EP_HasFunc)) & (*TExpr)(unsafe.Pointer(pLeft)).Fflags
|
|
if (*TExpr)(unsafe.Pointer(pLeft)).FnHeight >= (*TExpr)(unsafe.Pointer(pRoot)).FnHeight {
|
|
(*TExpr)(unsafe.Pointer(pRoot)).FnHeight = (*TExpr)(unsafe.Pointer(pLeft)).FnHeight + int32(1)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will evaluate expression pExpr and store the
|
|
// ** results in register target. The results are guaranteed to appear
|
|
// ** in register target.
|
|
// */
|
|
func _sqlite3ExprCode(tls *libc.TLS, pParse uintptr, pExpr uintptr, target int32) {
|
|
var inReg int32
|
|
var op Tu8
|
|
var pX uintptr
|
|
_, _, _ = inReg, op, pX
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpVdbe == uintptr(0) {
|
|
return
|
|
}
|
|
inReg = _sqlite3ExprCodeTarget(tls, pParse, pExpr, target)
|
|
if inReg != target {
|
|
pX = _sqlite3ExprSkipCollateAndLikely(tls, pExpr)
|
|
if pX != 0 && ((*TExpr)(unsafe.Pointer(pX)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subquery)) != uint32(0) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pX)).Fop) == int32(TK_REGISTER)) {
|
|
op = uint8(OP_Copy)
|
|
} else {
|
|
op = uint8(OP_SCopy)
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, libc.Int32FromUint8(op), inReg, target)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will extract the iColumn-th column from
|
|
// ** table pTab and store the column value in register iReg.
|
|
// **
|
|
// ** There must be an open cursor to pTab in iTable when this routine
|
|
// ** is called. If iColumn<0 then code is generated that extracts the rowid.
|
|
// */
|
|
func _sqlite3ExprCodeGetColumn(tls *libc.TLS, pParse uintptr, pTab uintptr, iColumn int32, iTable int32, iReg int32, p5 Tu8) (r int32) {
|
|
var pOp uintptr
|
|
_ = pOp
|
|
_sqlite3ExprCodeGetColumnOfTable(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, pTab, iTable, iColumn, iReg)
|
|
if p5 != 0 {
|
|
pOp = _sqlite3VdbeGetLastOp(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe)
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode) == int32(OP_Column) {
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp5 = uint16(p5)
|
|
}
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode) == int32(OP_VColumn) {
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp5 = libc.Uint16FromInt32(libc.Int32FromUint8(p5) & libc.Int32FromInt32(OPFLAG_NOCHNG))
|
|
}
|
|
}
|
|
return iReg
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Expression p is a comparison operator. Return a collation sequence
|
|
// ** appropriate for the comparison operator.
|
|
// **
|
|
// ** This is normally just a wrapper around sqlite3BinaryCompareCollSeq().
|
|
// ** However, if the OP_Commuted flag is set, then the order of the operands
|
|
// ** is reversed in the sqlite3BinaryCompareCollSeq() call so that the
|
|
// ** correct collating sequence is found.
|
|
// */
|
|
func _sqlite3ExprCompareCollSeq(tls *libc.TLS, pParse uintptr, p uintptr) (r uintptr) {
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Commuted)) != uint32(0) {
|
|
return _sqlite3BinaryCompareCollSeq(tls, pParse, (*TExpr)(unsafe.Pointer(p)).FpRight, (*TExpr)(unsafe.Pointer(p)).FpLeft)
|
|
} else {
|
|
return _sqlite3BinaryCompareCollSeq(tls, pParse, (*TExpr)(unsafe.Pointer(p)).FpLeft, (*TExpr)(unsafe.Pointer(p)).FpRight)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the input expression is an ID with the name "true" or "false"
|
|
// ** then convert it into an TK_TRUEFALSE term. Return non-zero if
|
|
// ** the conversion happened, and zero if the expression is unaltered.
|
|
// */
|
|
func _sqlite3ExprIdToTrueFalse(tls *libc.TLS, pExpr uintptr) (r int32) {
|
|
var v, v1 Tu32
|
|
var v2 bool
|
|
_, _, _ = v, v1, v2
|
|
if v2 = !((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Quoted)|libc.Int32FromInt32(EP_IntValue)) != libc.Uint32FromInt32(0)); v2 {
|
|
v1 = _sqlite3IsTrueOrFalse(tls, *(*uintptr)(unsafe.Pointer(pExpr + 8)))
|
|
v = v1
|
|
}
|
|
if v2 && v1 != uint32(0) {
|
|
(*TExpr)(unsafe.Pointer(pExpr)).Fop = uint8(TK_TRUEFALSE)
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= v
|
|
return int32(1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for a boolean expression such that a jump is made
|
|
// ** to the label "dest" if the expression is false but execution
|
|
// ** continues straight thru if the expression is true.
|
|
// **
|
|
// ** If the expression evaluates to NULL (neither true nor false) then
|
|
// ** jump if jumpIfNull is SQLITE_JUMPIFNULL or fall through if jumpIfNull
|
|
// ** is 0.
|
|
// */
|
|
func _sqlite3ExprIfFalse(tls *libc.TLS, pParse uintptr, pExpr uintptr, dest int32, jumpIfNull int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var addrIsNull, d2, destIfNull, isNot, isTrue, op, v19 int32
|
|
var pAlt, pFirst, pSecond, v uintptr
|
|
var _ /* r1 at bp+8 */ int32
|
|
var _ /* r2 at bp+12 */ int32
|
|
var _ /* regFree1 at bp+0 */ int32
|
|
var _ /* regFree2 at bp+4 */ int32
|
|
_, _, _, _, _, _, _, _, _, _, _ = addrIsNull, d2, destIfNull, isNot, isTrue, op, pAlt, pFirst, pSecond, v, v19
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
op = 0
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
**(**int32)(__ccgo_up(bp + 4)) = 0
|
|
if v == uintptr(0) {
|
|
return
|
|
} /* Existence of VDBE checked by caller */
|
|
if pExpr == uintptr(0) {
|
|
return
|
|
}
|
|
/* The value of pExpr->op and op are related as follows:
|
|
**
|
|
** pExpr->op op
|
|
** --------- ----------
|
|
** TK_ISNULL OP_NotNull
|
|
** TK_NOTNULL OP_IsNull
|
|
** TK_NE OP_Eq
|
|
** TK_EQ OP_Ne
|
|
** TK_GT OP_Le
|
|
** TK_LE OP_Gt
|
|
** TK_GE OP_Lt
|
|
** TK_LT OP_Ge
|
|
**
|
|
** For other values of pExpr->op, op is undefined and unused.
|
|
** The value of TK_ and OP_ constants are arranged such that we
|
|
** can compute the mapping above using the following expression.
|
|
** Assert()s verify that the computation is correct.
|
|
*/
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) + libc.Int32FromInt32(TK_ISNULL)&libc.Int32FromInt32(1) ^ int32(1) - libc.Int32FromInt32(TK_ISNULL)&libc.Int32FromInt32(1)
|
|
/* Verify correct alignment of TK_ and OP_ constants
|
|
*/
|
|
switch libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) {
|
|
case int32(TK_OR):
|
|
goto _1
|
|
case int32(TK_AND):
|
|
goto _2
|
|
case int32(TK_NOT):
|
|
goto _3
|
|
case int32(TK_TRUTH):
|
|
goto _4
|
|
case int32(TK_ISNOT):
|
|
goto _5
|
|
case int32(TK_IS):
|
|
goto _6
|
|
case int32(TK_EQ):
|
|
goto _7
|
|
case int32(TK_NE):
|
|
goto _8
|
|
case int32(TK_GE):
|
|
goto _9
|
|
case int32(TK_GT):
|
|
goto _10
|
|
case int32(TK_LE):
|
|
goto _11
|
|
case int32(TK_LT):
|
|
goto _12
|
|
case int32(TK_NOTNULL):
|
|
goto _13
|
|
case int32(TK_ISNULL):
|
|
goto _14
|
|
case int32(TK_BETWEEN):
|
|
goto _15
|
|
case int32(TK_IN):
|
|
goto _16
|
|
default:
|
|
goto _17
|
|
}
|
|
goto _18
|
|
_2:
|
|
;
|
|
_1:
|
|
;
|
|
pAlt = _sqlite3ExprSimplifiedAndOr(tls, pExpr)
|
|
if pAlt != pExpr {
|
|
_sqlite3ExprIfFalse(tls, pParse, pAlt, dest, jumpIfNull)
|
|
} else {
|
|
if _exprEvalRhsFirst(tls, pExpr) != 0 {
|
|
pFirst = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
pSecond = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
} else {
|
|
pFirst = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
pSecond = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AND) {
|
|
_sqlite3ExprIfFalse(tls, pParse, pFirst, dest, jumpIfNull)
|
|
_sqlite3ExprIfFalse(tls, pParse, pSecond, dest, jumpIfNull)
|
|
} else {
|
|
d2 = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
_sqlite3ExprIfTrue(tls, pParse, pFirst, d2, jumpIfNull^int32(SQLITE_JUMPIFNULL))
|
|
_sqlite3ExprIfFalse(tls, pParse, pSecond, dest, jumpIfNull)
|
|
_sqlite3VdbeResolveLabel(tls, v, d2)
|
|
}
|
|
}
|
|
goto _18
|
|
_3:
|
|
;
|
|
_sqlite3ExprIfTrue(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, dest, jumpIfNull)
|
|
goto _18
|
|
_4:
|
|
; /* IS TRUE or IS NOT TRUE */
|
|
isNot = libc.BoolInt32(libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop2) == int32(TK_ISNOT))
|
|
isTrue = _sqlite3ExprTruthValue(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpRight)
|
|
if isTrue^isNot != 0 {
|
|
/* IS TRUE and IS NOT FALSE */
|
|
if isNot != 0 {
|
|
v19 = 0
|
|
} else {
|
|
v19 = int32(SQLITE_JUMPIFNULL)
|
|
}
|
|
_sqlite3ExprIfFalse(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, dest, v19)
|
|
} else {
|
|
/* IS FALSE and IS NOT TRUE */
|
|
if isNot != 0 {
|
|
v19 = 0
|
|
} else {
|
|
v19 = int32(SQLITE_JUMPIFNULL)
|
|
}
|
|
_sqlite3ExprIfTrue(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, dest, v19)
|
|
}
|
|
goto _18
|
|
_6:
|
|
;
|
|
_5:
|
|
;
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_IS) {
|
|
v19 = int32(TK_NE)
|
|
} else {
|
|
v19 = int32(TK_EQ)
|
|
}
|
|
op = v19
|
|
jumpIfNull = int32(SQLITE_NULLEQ)
|
|
_12:
|
|
;
|
|
_11:
|
|
;
|
|
_10:
|
|
;
|
|
_9:
|
|
;
|
|
_8:
|
|
;
|
|
_7:
|
|
;
|
|
if _sqlite3ExprIsVector(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft) != 0 {
|
|
goto default_expr
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subquery)) != uint32(0) && jumpIfNull != int32(SQLITE_NULLEQ) {
|
|
addrIsNull = _exprComputeOperands(tls, pParse, pExpr, bp+8, bp+12, bp, bp+4)
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, bp)
|
|
**(**int32)(__ccgo_up(bp + 12)) = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, bp+4)
|
|
addrIsNull = 0
|
|
}
|
|
_codeCompare(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, op, **(**int32)(__ccgo_up(bp + 8)), **(**int32)(__ccgo_up(bp + 12)), dest, jumpIfNull, libc.BoolInt32((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Commuted)) != uint32(0)))
|
|
if addrIsNull != 0 {
|
|
if jumpIfNull != 0 {
|
|
_sqlite3VdbeChangeP2(tls, v, addrIsNull, dest)
|
|
} else {
|
|
_sqlite3VdbeJumpHere(tls, v, addrIsNull)
|
|
}
|
|
}
|
|
goto _18
|
|
_14:
|
|
;
|
|
_13:
|
|
;
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, bp)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
_sqlite3VdbeTypeofColumn(tls, v, **(**int32)(__ccgo_up(bp + 8)))
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, op, **(**int32)(__ccgo_up(bp + 8)), dest)
|
|
goto _18
|
|
_15:
|
|
;
|
|
_exprCodeBetween(tls, pParse, pExpr, dest, __ccgo_fp(_sqlite3ExprIfFalse), jumpIfNull)
|
|
goto _18
|
|
_16:
|
|
;
|
|
if jumpIfNull != 0 {
|
|
_sqlite3ExprCodeIN(tls, pParse, pExpr, dest, dest)
|
|
} else {
|
|
destIfNull = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
_sqlite3ExprCodeIN(tls, pParse, pExpr, dest, destIfNull)
|
|
_sqlite3VdbeResolveLabel(tls, v, destIfNull)
|
|
}
|
|
goto _18
|
|
_17:
|
|
;
|
|
goto default_expr
|
|
default_expr:
|
|
;
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsFalse)) == uint32(EP_IsFalse) {
|
|
_sqlite3VdbeGoto(tls, v, dest)
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsTrue)) == uint32(EP_IsTrue) {
|
|
/* no-op */
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3ExprCodeTemp(tls, pParse, pExpr, bp)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_IfNot), **(**int32)(__ccgo_up(bp + 8)), dest, libc.BoolInt32(jumpIfNull != 0))
|
|
}
|
|
}
|
|
goto _18
|
|
_18:
|
|
;
|
|
_sqlite3ReleaseTempReg(tls, pParse, **(**int32)(__ccgo_up(bp)))
|
|
_sqlite3ReleaseTempReg(tls, pParse, **(**int32)(__ccgo_up(bp + 4)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Like sqlite3ExprIfFalse() except that a copy is made of pExpr before
|
|
// ** code generation, and that copy is deleted after code generation. This
|
|
// ** ensures that the original pExpr is unchanged.
|
|
// */
|
|
func _sqlite3ExprIfFalseDup(tls *libc.TLS, pParse uintptr, pExpr uintptr, dest int32, jumpIfNull int32) {
|
|
var db, pCopy uintptr
|
|
_, _ = db, pCopy
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pCopy = _sqlite3ExprDup(tls, db, pExpr, 0)
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed) == 0 {
|
|
_sqlite3ExprIfFalse(tls, pParse, pCopy, dest, jumpIfNull)
|
|
}
|
|
_sqlite3ExprDelete(tls, db, pCopy)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for a boolean expression such that a jump is made
|
|
// ** to the label "dest" if the expression is true but execution
|
|
// ** continues straight thru if the expression is false.
|
|
// **
|
|
// ** If the expression evaluates to NULL (neither true nor false), then
|
|
// ** take the jump if the jumpIfNull flag is SQLITE_JUMPIFNULL.
|
|
// **
|
|
// ** This code depends on the fact that certain token values (ex: TK_EQ)
|
|
// ** are the same as opcode values (ex: OP_Eq) that implement the corresponding
|
|
// ** operation. Special comments in vdbe.c and the mkopcodeh.awk script in
|
|
// ** the make process cause these values to align. Assert()s in the code
|
|
// ** below verify that the numbers are aligned correctly.
|
|
// */
|
|
func _sqlite3ExprIfTrue(tls *libc.TLS, pParse uintptr, pExpr uintptr, dest int32, jumpIfNull int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var addrIsNull, d2, destIfFalse, destIfNull, isNot, isTrue, op, v19 int32
|
|
var pAlt, pFirst, pSecond, v uintptr
|
|
var _ /* r1 at bp+8 */ int32
|
|
var _ /* r2 at bp+12 */ int32
|
|
var _ /* regFree1 at bp+0 */ int32
|
|
var _ /* regFree2 at bp+4 */ int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = addrIsNull, d2, destIfFalse, destIfNull, isNot, isTrue, op, pAlt, pFirst, pSecond, v, v19
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
op = 0
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
**(**int32)(__ccgo_up(bp + 4)) = 0
|
|
if v == uintptr(0) {
|
|
return
|
|
} /* Existence of VDBE checked by caller */
|
|
if pExpr == uintptr(0) {
|
|
return
|
|
} /* No way this can happen */
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop)
|
|
switch op {
|
|
case int32(TK_OR):
|
|
goto _1
|
|
case int32(TK_AND):
|
|
goto _2
|
|
case int32(TK_NOT):
|
|
goto _3
|
|
case int32(TK_TRUTH):
|
|
goto _4
|
|
case int32(TK_ISNOT):
|
|
goto _5
|
|
case int32(TK_IS):
|
|
goto _6
|
|
case int32(TK_EQ):
|
|
goto _7
|
|
case int32(TK_NE):
|
|
goto _8
|
|
case int32(TK_GE):
|
|
goto _9
|
|
case int32(TK_GT):
|
|
goto _10
|
|
case int32(TK_LE):
|
|
goto _11
|
|
case int32(TK_LT):
|
|
goto _12
|
|
case int32(TK_NOTNULL):
|
|
goto _13
|
|
case int32(TK_ISNULL):
|
|
goto _14
|
|
case int32(TK_BETWEEN):
|
|
goto _15
|
|
case int32(TK_IN):
|
|
goto _16
|
|
default:
|
|
goto _17
|
|
}
|
|
goto _18
|
|
_2:
|
|
;
|
|
_1:
|
|
;
|
|
pAlt = _sqlite3ExprSimplifiedAndOr(tls, pExpr)
|
|
if pAlt != pExpr {
|
|
_sqlite3ExprIfTrue(tls, pParse, pAlt, dest, jumpIfNull)
|
|
} else {
|
|
if _exprEvalRhsFirst(tls, pExpr) != 0 {
|
|
pFirst = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
pSecond = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
} else {
|
|
pFirst = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
pSecond = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
}
|
|
if op == int32(TK_AND) {
|
|
d2 = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
_sqlite3ExprIfFalse(tls, pParse, pFirst, d2, jumpIfNull^int32(SQLITE_JUMPIFNULL))
|
|
_sqlite3ExprIfTrue(tls, pParse, pSecond, dest, jumpIfNull)
|
|
_sqlite3VdbeResolveLabel(tls, v, d2)
|
|
} else {
|
|
_sqlite3ExprIfTrue(tls, pParse, pFirst, dest, jumpIfNull)
|
|
_sqlite3ExprIfTrue(tls, pParse, pSecond, dest, jumpIfNull)
|
|
}
|
|
}
|
|
goto _18
|
|
_3:
|
|
;
|
|
_sqlite3ExprIfFalse(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, dest, jumpIfNull)
|
|
goto _18
|
|
_4:
|
|
; /* IS TRUE or IS NOT TRUE */
|
|
isNot = libc.BoolInt32(libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop2) == int32(TK_ISNOT))
|
|
isTrue = _sqlite3ExprTruthValue(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpRight)
|
|
if isTrue^isNot != 0 {
|
|
if isNot != 0 {
|
|
v19 = int32(SQLITE_JUMPIFNULL)
|
|
} else {
|
|
v19 = 0
|
|
}
|
|
_sqlite3ExprIfTrue(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, dest, v19)
|
|
} else {
|
|
if isNot != 0 {
|
|
v19 = int32(SQLITE_JUMPIFNULL)
|
|
} else {
|
|
v19 = 0
|
|
}
|
|
_sqlite3ExprIfFalse(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, dest, v19)
|
|
}
|
|
goto _18
|
|
_6:
|
|
;
|
|
_5:
|
|
;
|
|
if op == int32(TK_IS) {
|
|
v19 = int32(TK_EQ)
|
|
} else {
|
|
v19 = int32(TK_NE)
|
|
}
|
|
op = v19
|
|
jumpIfNull = int32(SQLITE_NULLEQ)
|
|
_12:
|
|
;
|
|
_11:
|
|
;
|
|
_10:
|
|
;
|
|
_9:
|
|
;
|
|
_8:
|
|
;
|
|
_7:
|
|
;
|
|
if _sqlite3ExprIsVector(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft) != 0 {
|
|
goto default_expr
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subquery)) != uint32(0) && jumpIfNull != int32(SQLITE_NULLEQ) {
|
|
addrIsNull = _exprComputeOperands(tls, pParse, pExpr, bp+8, bp+12, bp, bp+4)
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, bp)
|
|
**(**int32)(__ccgo_up(bp + 12)) = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, bp+4)
|
|
addrIsNull = 0
|
|
}
|
|
_codeCompare(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, op, **(**int32)(__ccgo_up(bp + 8)), **(**int32)(__ccgo_up(bp + 12)), dest, jumpIfNull, libc.BoolInt32((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Commuted)) != uint32(0)))
|
|
if addrIsNull != 0 {
|
|
if jumpIfNull != 0 {
|
|
_sqlite3VdbeChangeP2(tls, v, addrIsNull, dest)
|
|
} else {
|
|
_sqlite3VdbeJumpHere(tls, v, addrIsNull)
|
|
}
|
|
}
|
|
goto _18
|
|
_14:
|
|
;
|
|
_13:
|
|
;
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3ExprCodeTemp(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, bp)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
_sqlite3VdbeTypeofColumn(tls, v, **(**int32)(__ccgo_up(bp + 8)))
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, op, **(**int32)(__ccgo_up(bp + 8)), dest)
|
|
goto _18
|
|
_15:
|
|
;
|
|
_exprCodeBetween(tls, pParse, pExpr, dest, __ccgo_fp(_sqlite3ExprIfTrue), jumpIfNull)
|
|
goto _18
|
|
_16:
|
|
;
|
|
destIfFalse = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
if jumpIfNull != 0 {
|
|
v19 = dest
|
|
} else {
|
|
v19 = destIfFalse
|
|
}
|
|
destIfNull = v19
|
|
_sqlite3ExprCodeIN(tls, pParse, pExpr, destIfFalse, destIfNull)
|
|
_sqlite3VdbeGoto(tls, v, dest)
|
|
_sqlite3VdbeResolveLabel(tls, v, destIfFalse)
|
|
goto _18
|
|
_17:
|
|
;
|
|
goto default_expr
|
|
default_expr:
|
|
;
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsTrue)) == uint32(EP_IsTrue) {
|
|
_sqlite3VdbeGoto(tls, v, dest)
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsFalse)) == uint32(EP_IsFalse) {
|
|
/* No-op */
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3ExprCodeTemp(tls, pParse, pExpr, bp)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_If), **(**int32)(__ccgo_up(bp + 8)), dest, libc.BoolInt32(jumpIfNull != 0))
|
|
}
|
|
}
|
|
goto _18
|
|
_18:
|
|
;
|
|
_sqlite3ReleaseTempReg(tls, pParse, **(**int32)(__ccgo_up(bp)))
|
|
_sqlite3ReleaseTempReg(tls, pParse, **(**int32)(__ccgo_up(bp + 4)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walk an expression tree for the DEFAULT field of a column definition
|
|
// ** in a CREATE TABLE statement. Return non-zero if the expression is
|
|
// ** acceptable for use as a DEFAULT. That is to say, return non-zero if
|
|
// ** the expression is constant or a function call with constant arguments.
|
|
// ** Return and 0 if there are any variables.
|
|
// **
|
|
// ** isInit is true when parsing from sqlite_schema. isInit is false when
|
|
// ** processing a new CREATE TABLE statement. When isInit is true, parameters
|
|
// ** (such as ? or $abc) in the expression are converted into NULL. When
|
|
// ** isInit is false, parameters raise an error. Parameters should not be
|
|
// ** allowed in a CREATE TABLE statement, but some legacy versions of SQLite
|
|
// ** allowed it, so we need to support it when reading sqlite_schema for
|
|
// ** backwards compatibility.
|
|
// **
|
|
// ** If isInit is true, set EP_FromDDL on every TK_FUNCTION node.
|
|
// **
|
|
// ** For the purposes of this function, a double-quoted string (ex: "abc")
|
|
// ** is considered a variable but a single-quoted string (ex: 'abc') is
|
|
// ** a constant.
|
|
// */
|
|
func _sqlite3ExprIsConstantOrFunction(tls *libc.TLS, p uintptr, isInit Tu8) (r int32) {
|
|
return _exprIsConst(tls, uintptr(0), p, int32(4)+libc.Int32FromUint8(isInit))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the boolean value of the expression is always either
|
|
// ** FALSE or NULL.
|
|
// */
|
|
func _sqlite3ExprIsNotTrue(tls *libc.TLS, pExpr uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var _ /* v at bp+0 */ int32
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_NULL) {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_TRUEFALSE) && _sqlite3ExprTruthValue(tls, pExpr) == 0 {
|
|
return int32(1)
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = int32(1)
|
|
if _sqlite3ExprIsInteger(tls, pExpr, bp, uintptr(0)) != 0 && **(**int32)(__ccgo_up(bp)) == 0 {
|
|
return int32(1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If pExpr is an AND or OR expression, try to simplify it by eliminating
|
|
// ** terms that are always true or false. Return the simplified expression.
|
|
// ** Or return the original expression if no simplification is possible.
|
|
// **
|
|
// ** Examples:
|
|
// **
|
|
// ** (x<10) AND true => (x<10)
|
|
// ** (x<10) AND false => false
|
|
// ** (x<10) AND (y=22 OR false) => (x<10) AND (y=22)
|
|
// ** (x<10) AND (y=22 OR true) => (x<10)
|
|
// ** (y=22) OR true => true
|
|
// */
|
|
func _sqlite3ExprSimplifiedAndOr(tls *libc.TLS, pExpr uintptr) (r uintptr) {
|
|
var pLeft, pRight, v1 uintptr
|
|
_, _, _ = pLeft, pRight, v1
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AND) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_OR) {
|
|
pRight = _sqlite3ExprSimplifiedAndOr(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpRight)
|
|
pLeft = _sqlite3ExprSimplifiedAndOr(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft)
|
|
if (*TExpr)(unsafe.Pointer(pLeft)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsTrue)) == uint32(EP_IsTrue) || (*TExpr)(unsafe.Pointer(pRight)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsFalse)) == uint32(EP_IsFalse) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AND) {
|
|
v1 = pRight
|
|
} else {
|
|
v1 = pLeft
|
|
}
|
|
pExpr = v1
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(pRight)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsTrue)) == uint32(EP_IsTrue) || (*TExpr)(unsafe.Pointer(pLeft)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsFalse)) == uint32(EP_IsFalse) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AND) {
|
|
v1 = pLeft
|
|
} else {
|
|
v1 = pRight
|
|
}
|
|
pExpr = v1
|
|
}
|
|
}
|
|
}
|
|
return pExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Skip over any TK_COLLATE operators.
|
|
// */
|
|
func _sqlite3ExprSkipCollate(tls *libc.TLS, pExpr uintptr) (r uintptr) {
|
|
for pExpr != 0 && (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Skip)) != uint32(0) {
|
|
pExpr = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
}
|
|
return pExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert a scalar expression node to a TK_REGISTER referencing
|
|
// ** register iReg. The caller must ensure that iReg already contains
|
|
// ** the correct value for the expression.
|
|
// */
|
|
func _sqlite3ExprToRegister(tls *libc.TLS, pExpr uintptr, iReg int32) {
|
|
var p uintptr
|
|
_ = p
|
|
p = _sqlite3ExprSkipCollateAndLikely(tls, pExpr)
|
|
if p == uintptr(0) {
|
|
return
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_REGISTER) {
|
|
} else {
|
|
(*TExpr)(unsafe.Pointer(p)).Fop2 = (*TExpr)(unsafe.Pointer(p)).Fop
|
|
(*TExpr)(unsafe.Pointer(p)).Fop = uint8(TK_REGISTER)
|
|
(*TExpr)(unsafe.Pointer(p)).FiTable = iReg
|
|
**(**Tu32)(__ccgo_up(p + 4)) &= ^libc.Uint32FromInt32(libc.Int32FromInt32(EP_Skip))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
|
|
// ** expression.
|
|
// */
|
|
func _sqlite3ExprUnmapAndDelete(tls *libc.TLS, pParse uintptr, p uintptr) {
|
|
if p != 0 {
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
_sqlite3RenameExprUnmap(tls, pParse, p)
|
|
}
|
|
_sqlite3ExprDeleteNN(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, p)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Given m and e, which represent a quantity r == m*pow(2,e),
|
|
// ** return values *pD and *pP such that r == (*pD)*pow(10,*pP),
|
|
// ** approximately. *pD should contain at least n significant digits.
|
|
// **
|
|
// ** The input m is required to have its highest bit set. In other words,
|
|
// ** m should be left-shifted, and e decremented, to maximize the value of m.
|
|
// */
|
|
func _sqlite3Fp2Convert10(tls *libc.TLS, m Tu64, e int32, n int32, pD uintptr, pP uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var h Tu64
|
|
var p int32
|
|
var _ /* d1 at bp+0 */ Tu64
|
|
var _ /* d2 at bp+8 */ Tu32
|
|
_, _ = h, p
|
|
p = n - int32(1) - _pwr2to10(tls, e+int32(63))
|
|
h = _sqlite3Multiply128(tls, m, _powerOfTen(tls, p, bp+8), bp)
|
|
if n == int32(18) {
|
|
h = h >> libc.Uint64FromInt32(-(e + _pwr10to2(tls, p) + libc.Int32FromInt32(2)))
|
|
**(**Tu64)(__ccgo_up(pD)) = (h + h<<libc.Int32FromInt32(1)&uint64(2)) >> int32(1)
|
|
} else {
|
|
**(**Tu64)(__ccgo_up(pD)) = h >> -(e + _pwr10to2(tls, p) + int32(1))
|
|
}
|
|
**(**int32)(__ccgo_up(pP)) = -p
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the buffer to contain nData/pData. If an OOM error occurs, leave an
|
|
// ** the error code in p. If an error has already occurred when this function
|
|
// ** is called, it is a no-op.
|
|
// */
|
|
func _sqlite3Fts5BufferSet(tls *libc.TLS, pRc uintptr, pBuf uintptr, nData int32, pData uintptr) {
|
|
(*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn = 0
|
|
_sqlite3Fts5BufferAppendBlob(tls, pRc, pBuf, libc.Uint32FromInt32(nData), pData)
|
|
}
|
|
|
|
func _sqlite3Fts5BufferSize(tls *libc.TLS, pRc uintptr, pBuf uintptr, nByte Tu32) (r int32) {
|
|
var nNew Tu64
|
|
var pNew uintptr
|
|
var v1 int32
|
|
_, _, _ = nNew, pNew, v1
|
|
if libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pBuf)).FnSpace) < nByte {
|
|
if (*TFts5Buffer)(unsafe.Pointer(pBuf)).FnSpace != 0 {
|
|
v1 = (*TFts5Buffer)(unsafe.Pointer(pBuf)).FnSpace
|
|
} else {
|
|
v1 = int32(64)
|
|
}
|
|
nNew = libc.Uint64FromInt32(v1)
|
|
for nNew < uint64(nByte) {
|
|
nNew = nNew * uint64(2)
|
|
}
|
|
pNew = Xsqlite3_realloc64(tls, (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp, nNew)
|
|
if pNew == uintptr(0) {
|
|
**(**int32)(__ccgo_up(pRc)) = int32(SQLITE_NOMEM)
|
|
return int32(1)
|
|
} else {
|
|
(*TFts5Buffer)(unsafe.Pointer(pBuf)).FnSpace = libc.Int32FromUint64(nNew)
|
|
(*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp = pNew
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func _sqlite3Fts5Get32(tls *libc.TLS, aBuf uintptr) (r int32) {
|
|
return libc.Int32FromUint32(uint32(**(**Tu8)(__ccgo_up(aBuf)))<<libc.Int32FromInt32(24) + libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aBuf + 1)))<<libc.Int32FromInt32(16)) + libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aBuf + 2)))<<libc.Int32FromInt32(8)) + uint32(**(**Tu8)(__ccgo_up(aBuf + 3))))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is a copy of the sqlite3GetVarint32() routine from the SQLite core.
|
|
// ** Except, this version does handle the single byte case that the core
|
|
// ** version depends on being handled before its function is called.
|
|
// */
|
|
func _sqlite3Fts5GetVarint32(tls *libc.TLS, p uintptr, v uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var a, b Tu32
|
|
var n Tu8
|
|
var _ /* v64 at bp+0 */ Tu64
|
|
_, _, _ = a, b, n
|
|
/* The 1-byte case. Overwhelmingly the most common. */
|
|
a = uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* a: p0 (unmasked) */
|
|
if !(a&libc.Uint32FromInt32(0x80) != 0) {
|
|
/* Values between 0 and 127 */
|
|
**(**Tu32)(__ccgo_up(v)) = a
|
|
return int32(1)
|
|
}
|
|
/* The 2-byte case */
|
|
p = p + 1
|
|
b = uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* b: p1 (unmasked) */
|
|
if !(b&libc.Uint32FromInt32(0x80) != 0) {
|
|
/* Values between 128 and 16383 */
|
|
a = a & uint32(0x7f)
|
|
a = a << int32(7)
|
|
**(**Tu32)(__ccgo_up(v)) = a | b
|
|
return int32(2)
|
|
}
|
|
/* The 3-byte case */
|
|
p = p + 1
|
|
a = a << int32(14)
|
|
a = a | uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* a: p0<<14 | p2 (unmasked) */
|
|
if !(a&libc.Uint32FromInt32(0x80) != 0) {
|
|
/* Values between 16384 and 2097151 */
|
|
a = a & libc.Uint32FromInt32(libc.Int32FromInt32(0x7f)<<libc.Int32FromInt32(14)|libc.Int32FromInt32(0x7f))
|
|
b = b & uint32(0x7f)
|
|
b = b << int32(7)
|
|
**(**Tu32)(__ccgo_up(v)) = a | b
|
|
return int32(3)
|
|
}
|
|
/* A 32-bit varint is used to store size information in btrees.
|
|
** Objects are rarely larger than 2MiB limit of a 3-byte varint.
|
|
** A 3-byte varint is sufficient, for example, to record the size
|
|
** of a 1048569-byte BLOB or string.
|
|
**
|
|
** We only unroll the first 1-, 2-, and 3- byte cases. The very
|
|
** rare larger cases can be handled by the slower 64-bit varint
|
|
** routine.
|
|
*/
|
|
p = p - uintptr(2)
|
|
n = _sqlite3Fts5GetVarint(tls, p, bp)
|
|
**(**Tu32)(__ccgo_up(v)) = uint32(**(**Tu64)(__ccgo_up(bp))) & uint32(0x7FFFFFFF)
|
|
return libc.Int32FromUint8(n)
|
|
return r
|
|
}
|
|
|
|
/*
|
|
** Bitmasks used by sqlite3GetVarint(). These precomputed constants
|
|
** are defined here rather than simply putting the constant expressions
|
|
** inline in order to work around bugs in the RVT compiler.
|
|
**
|
|
** SLOT_2_0 A mask for (0x7f<<14) | 0x7f
|
|
**
|
|
** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0
|
|
*/
|
|
|
|
func _sqlite3Fts5GetVarintLen(tls *libc.TLS, iVal Tu32) (r int32) {
|
|
if iVal < libc.Uint32FromInt32(libc.Int32FromInt32(1)<<libc.Int32FromInt32(14)) {
|
|
return int32(2)
|
|
}
|
|
if iVal < libc.Uint32FromInt32(libc.Int32FromInt32(1)<<libc.Int32FromInt32(21)) {
|
|
return int32(3)
|
|
}
|
|
if iVal < libc.Uint32FromInt32(libc.Int32FromInt32(1)<<libc.Int32FromInt32(28)) {
|
|
return int32(4)
|
|
}
|
|
return int32(5)
|
|
}
|
|
|
|
/*
|
|
** 2015 May 08
|
|
**
|
|
** 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 virtual table module implementing direct access to an
|
|
** existing FTS5 index. The module may create several different types of
|
|
** tables:
|
|
**
|
|
** col:
|
|
** CREATE TABLE vocab(term, col, doc, cnt, PRIMARY KEY(term, col));
|
|
**
|
|
** One row for each term/column combination. The value of $doc is set to
|
|
** the number of fts5 rows that contain at least one instance of term
|
|
** $term within column $col. Field $cnt is set to the total number of
|
|
** instances of term $term in column $col (in any row of the fts5 table).
|
|
**
|
|
** row:
|
|
** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term));
|
|
**
|
|
** One row for each term in the database. The value of $doc is set to
|
|
** the number of fts5 rows that contain at least one instance of term
|
|
** $term. Field $cnt is set to the total number of instances of term
|
|
** $term in the database.
|
|
**
|
|
** instance:
|
|
** CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>));
|
|
**
|
|
** One row for each term instance in the database.
|
|
*/
|
|
|
|
/* #include "fts5Int.h" */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Retrieve the origin value that will be used for the segment currently
|
|
// ** being accumulated in the in-memory hash table when it is flushed to
|
|
// ** disk. If successful, SQLITE_OK is returned and (*piOrigin) set to
|
|
// ** the queried value. Or, if an error occurs, an error code is returned
|
|
// ** and the final value of (*piOrigin) is undefined.
|
|
// */
|
|
func _sqlite3Fts5IndexGetOrigin(tls *libc.TLS, p uintptr, piOrigin uintptr) (r int32) {
|
|
var pStruct uintptr
|
|
_ = pStruct
|
|
pStruct = _fts5StructureRead(tls, p)
|
|
if pStruct != 0 {
|
|
**(**Ti64)(__ccgo_up(piOrigin)) = libc.Int64FromUint64((*TFts5Structure)(unsafe.Pointer(pStruct)).FnOriginCntr)
|
|
_fts5StructureRelease(tls, pStruct)
|
|
}
|
|
return _fts5IndexReturn(tls, p)
|
|
}
|
|
|
|
func _sqlite3Fts5PoslistNext64(tls *libc.TLS, a uintptr, n int32, pi uintptr, piOff uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, v1 int32
|
|
var iOff Ti64
|
|
var _ /* iVal at bp+0 */ Tu32
|
|
_, _, _ = i, iOff, v1
|
|
i = **(**int32)(__ccgo_up(pi))
|
|
if i >= n {
|
|
/* EOF */
|
|
**(**Ti64)(__ccgo_up(piOff)) = int64(-int32(1))
|
|
return int32(1)
|
|
} else {
|
|
iOff = **(**Ti64)(__ccgo_up(piOff))
|
|
v1 = i
|
|
i = i + 1
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(**(**Tu8)(__ccgo_up(a + uintptr(v1))))
|
|
if **(**Tu32)(__ccgo_up(bp))&uint32(0x80) != 0 {
|
|
i = i - 1
|
|
i = i + _sqlite3Fts5GetVarint32(tls, a+uintptr(i), bp)
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp)) <= uint32(1) {
|
|
if **(**Tu32)(__ccgo_up(bp)) == uint32(0) {
|
|
**(**int32)(__ccgo_up(pi)) = i
|
|
return 0
|
|
}
|
|
v1 = i
|
|
i = i + 1
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(**(**Tu8)(__ccgo_up(a + uintptr(v1))))
|
|
if **(**Tu32)(__ccgo_up(bp))&uint32(0x80) != 0 {
|
|
i = i - 1
|
|
i = i + _sqlite3Fts5GetVarint32(tls, a+uintptr(i), bp)
|
|
}
|
|
iOff = libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp))) << int32(32)
|
|
v1 = i
|
|
i = i + 1
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(**(**Tu8)(__ccgo_up(a + uintptr(v1))))
|
|
if **(**Tu32)(__ccgo_up(bp))&uint32(0x80) != 0 {
|
|
i = i - 1
|
|
i = i + _sqlite3Fts5GetVarint32(tls, a+uintptr(i), bp)
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp)) < uint32(2) {
|
|
/* This is a corrupt record. So stop parsing it here. */
|
|
**(**Ti64)(__ccgo_up(piOff)) = int64(-int32(1))
|
|
return int32(1)
|
|
}
|
|
**(**Ti64)(__ccgo_up(piOff)) = iOff + libc.Int64FromUint32((**(**Tu32)(__ccgo_up(bp))-libc.Uint32FromInt32(2))&libc.Uint32FromInt32(0x7FFFFFFF))
|
|
} else {
|
|
**(**Ti64)(__ccgo_up(piOff)) = iOff&(libc.Int64FromInt32(0x7FFFFFFF)<<libc.Int32FromInt32(32)) + (iOff+libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp))-libc.Uint32FromInt32(2)))&int64(0x7FFFFFFF)
|
|
}
|
|
**(**int32)(__ccgo_up(pi)) = i
|
|
return 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
func _sqlite3Fts5PoslistWriterAppend(tls *libc.TLS, pBuf uintptr, pWriter uintptr, iPos Ti64) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var v1 int32
|
|
var _ /* rc at bp+0 */ int32
|
|
_ = v1
|
|
**(**int32)(__ccgo_up(bp)) = 0 /* Initialized only to suppress erroneous warning from Clang */
|
|
if libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn)+libc.Uint32FromInt32(libc.Int32FromInt32(5)+libc.Int32FromInt32(5)+libc.Int32FromInt32(5)) <= libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pBuf)).FnSpace) {
|
|
v1 = 0
|
|
} else {
|
|
v1 = _sqlite3Fts5BufferSize(tls, bp, pBuf, libc.Uint32FromInt32(libc.Int32FromInt32(5)+libc.Int32FromInt32(5)+libc.Int32FromInt32(5)+(*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn))
|
|
}
|
|
if v1 != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
_sqlite3Fts5PoslistSafeAppend(tls, pBuf, pWriter, iPos)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
func _sqlite3Fts5Put32(tls *libc.TLS, aBuf uintptr, iVal int32) {
|
|
**(**Tu8)(__ccgo_up(aBuf)) = libc.Uint8FromInt32(iVal >> int32(24) & int32(0x00FF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 1)) = libc.Uint8FromInt32(iVal >> int32(16) & int32(0x00FF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 2)) = libc.Uint8FromInt32(iVal >> int32(8) & int32(0x00FF))
|
|
**(**Tu8)(__ccgo_up(aBuf + 3)) = libc.Uint8FromInt32(iVal >> 0 & int32(0x00FF))
|
|
}
|
|
|
|
func _sqlite3Fts5UnicodeAscii(tls *libc.TLS, aArray uintptr, aAscii uintptr) {
|
|
var bToken, i, iTbl, n int32
|
|
_, _, _, _ = bToken, i, iTbl, n
|
|
i = 0
|
|
iTbl = 0
|
|
for i < int32(128) {
|
|
bToken = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aArray + uintptr(libc.Int32FromUint16(_aFts5UnicodeData[iTbl])&int32(0x1F)))))
|
|
n = libc.Int32FromUint16(_aFts5UnicodeData[iTbl])>>int32(5) + i
|
|
for {
|
|
if !(i < int32(128) && i < n) {
|
|
break
|
|
}
|
|
**(**Tu8)(__ccgo_up(aAscii + uintptr(i))) = libc.Uint8FromInt32(bToken)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
iTbl = iTbl + 1
|
|
}
|
|
**(**Tu8)(__ccgo_up(aAscii)) = uint8(0) /* 0x00 is never a token character */
|
|
}
|
|
|
|
/*
|
|
** 2015 May 30
|
|
**
|
|
** 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.
|
|
**
|
|
******************************************************************************
|
|
**
|
|
** Routines for varint serialization and deserialization.
|
|
*/
|
|
|
|
/* #include "fts5Int.h" */
|
|
|
|
func _sqlite3Fts5UnicodeCategory(tls *libc.TLS, iCode Tu32) (r int32) {
|
|
var iHi, iLo, iRes, iTest, ret, v1 int32
|
|
var iKey Tu16
|
|
_, _, _, _, _, _, _ = iHi, iKey, iLo, iRes, iTest, ret, v1
|
|
iRes = -int32(1)
|
|
if iCode >= libc.Uint32FromInt32(libc.Int32FromInt32(1)<<libc.Int32FromInt32(20)) {
|
|
return 0
|
|
}
|
|
iLo = libc.Int32FromUint16(_aFts5UnicodeBlock[iCode>>int32(16)])
|
|
iHi = libc.Int32FromUint16(_aFts5UnicodeBlock[uint32(1)+iCode>>libc.Int32FromInt32(16)])
|
|
iKey = uint16(iCode & libc.Uint32FromInt32(0xFFFF))
|
|
for iHi > iLo {
|
|
iTest = (iHi + iLo) / int32(2)
|
|
if libc.Int32FromUint16(iKey) >= libc.Int32FromUint16(_aFts5UnicodeMap[iTest]) {
|
|
iRes = iTest
|
|
iLo = iTest + int32(1)
|
|
} else {
|
|
iHi = iTest
|
|
}
|
|
}
|
|
if iRes < 0 {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint16(iKey) >= libc.Int32FromUint16(_aFts5UnicodeMap[iRes])+libc.Int32FromUint16(_aFts5UnicodeData[iRes])>>int32(5) {
|
|
return 0
|
|
}
|
|
ret = libc.Int32FromUint16(_aFts5UnicodeData[iRes]) & int32(0x1F)
|
|
if ret != int32(30) {
|
|
return ret
|
|
}
|
|
if (libc.Int32FromUint16(iKey)-libc.Int32FromUint16(_aFts5UnicodeMap[iRes]))&int32(0x01) != 0 {
|
|
v1 = int32(5)
|
|
} else {
|
|
v1 = int32(9)
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the argument interpreted as a unicode codepoint
|
|
// ** is a diacritical modifier character.
|
|
// */
|
|
func _sqlite3Fts5UnicodeIsdiacritic(tls *libc.TLS, c int32) (r int32) {
|
|
var mask0, mask1, v1 uint32
|
|
_, _, _ = mask0, mask1, v1
|
|
mask0 = uint32(0x08029FDF)
|
|
mask1 = uint32(0x000361F8)
|
|
if c < int32(768) || c > int32(817) {
|
|
return 0
|
|
}
|
|
if c < libc.Int32FromInt32(768)+libc.Int32FromInt32(32) {
|
|
v1 = mask0 & (libc.Uint32FromInt32(1) << (c - int32(768)))
|
|
} else {
|
|
v1 = mask1 & (libc.Uint32FromInt32(1) << (c - int32(768) - int32(32)))
|
|
}
|
|
return libc.Int32FromUint32(v1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Interpret the given string as a boolean value.
|
|
// */
|
|
func _sqlite3GetBoolean(tls *libc.TLS, z uintptr, dflt Tu8) (r Tu8) {
|
|
return libc.BoolUint8(libc.Int32FromUint8(_getSafetyLevel(tls, z, int32(1), dflt)) != 0)
|
|
}
|
|
|
|
/* The sqlite3GetBoolean() function is used by other modules but the
|
|
** remainder of this file is specific to PRAGMA processing. So omit
|
|
** the rest of the file if PRAGMAs are omitted from the build.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the length (in bytes) of the token that begins at z[0].
|
|
// ** Store the token type in *tokenType before returning.
|
|
// */
|
|
func _sqlite3GetToken(tls *libc.TLS, z uintptr, tokenType uintptr) (r Ti64) {
|
|
var c, delim, v3 int32
|
|
var i, n Ti64
|
|
var v6 bool
|
|
_, _, _, _, _, _ = c, delim, i, n, v3, v6
|
|
switch libc.Int32FromUint8(_aiClass[**(**uint8)(__ccgo_up(z))]) { /* Switch on the character-class of the first byte
|
|
** of the token. See the comment on the CC_ defines
|
|
** above. */
|
|
case int32(CC_SPACE):
|
|
i = int64(1)
|
|
for {
|
|
if !(libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x01) != 0) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_SPACE)
|
|
return i
|
|
case int32(CC_MINUS):
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) == int32('-') {
|
|
i = int64(2)
|
|
for {
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i))))
|
|
c = v3
|
|
if !(v3 != 0 && c != int32('\n')) {
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_COMMENT)
|
|
return i
|
|
} else {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) == int32('>') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_PTR)
|
|
return int64(int32(2) + libc.BoolInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 2))) == int32('>')))
|
|
}
|
|
}
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_MINUS)
|
|
return int64(1)
|
|
case int32(CC_LP):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_LP)
|
|
return int64(1)
|
|
case int32(CC_RP):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_RP)
|
|
return int64(1)
|
|
case int32(CC_SEMI):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_SEMI)
|
|
return int64(1)
|
|
case int32(CC_PLUS):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_PLUS)
|
|
return int64(1)
|
|
case int32(CC_STAR):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_STAR)
|
|
return int64(1)
|
|
case int32(CC_SLASH):
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) != int32('*') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 2))) == 0 {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_SLASH)
|
|
return int64(1)
|
|
}
|
|
i = int64(3)
|
|
c = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 2)))
|
|
for {
|
|
if v6 = c != int32('*') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) != int32('/'); v6 {
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i))))
|
|
c = v3
|
|
}
|
|
if !(v6 && v3 != 0) {
|
|
break
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if c != 0 {
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_COMMENT)
|
|
return i
|
|
case int32(CC_PERCENT):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_REM)
|
|
return int64(1)
|
|
case int32(CC_EQ):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_EQ)
|
|
return int64(int32(1) + libc.BoolInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) == int32('=')))
|
|
case int32(CC_LT):
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1)))
|
|
c = v3
|
|
if v3 == int32('=') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_LE)
|
|
return int64(2)
|
|
} else {
|
|
if c == int32('>') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_NE)
|
|
return int64(2)
|
|
} else {
|
|
if c == int32('<') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_LSHIFT)
|
|
return int64(2)
|
|
} else {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_LT)
|
|
return int64(1)
|
|
}
|
|
}
|
|
}
|
|
fallthrough
|
|
case int32(CC_GT):
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1)))
|
|
c = v3
|
|
if v3 == int32('=') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_GE)
|
|
return int64(2)
|
|
} else {
|
|
if c == int32('>') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_RSHIFT)
|
|
return int64(2)
|
|
} else {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_GT)
|
|
return int64(1)
|
|
}
|
|
}
|
|
fallthrough
|
|
case int32(CC_BANG):
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) != int32('=') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ILLEGAL)
|
|
return int64(1)
|
|
} else {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_NE)
|
|
return int64(2)
|
|
}
|
|
fallthrough
|
|
case int32(CC_PIPE):
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) != int32('|') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_BITOR)
|
|
return int64(1)
|
|
} else {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_CONCAT)
|
|
return int64(2)
|
|
}
|
|
fallthrough
|
|
case int32(CC_COMMA):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_COMMA)
|
|
return int64(1)
|
|
case int32(CC_AND):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_BITAND)
|
|
return int64(1)
|
|
case int32(CC_TILDA):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_BITNOT)
|
|
return int64(1)
|
|
case int32(CC_QUOTE):
|
|
delim = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z)))
|
|
i = int64(1)
|
|
for {
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i))))
|
|
c = v3
|
|
if !(v3 != 0) {
|
|
break
|
|
}
|
|
if c == delim {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i+int64(1))))) == delim {
|
|
i = i + 1
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
goto _9
|
|
_9:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if c == int32('\'') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_STRING)
|
|
return i + int64(1)
|
|
} else {
|
|
if c != 0 {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ID)
|
|
return i + int64(1)
|
|
} else {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ILLEGAL)
|
|
return i
|
|
}
|
|
}
|
|
fallthrough
|
|
case int32(CC_DOT):
|
|
if !(libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + 1))])&libc.Int32FromInt32(0x04) != 0) {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_DOT)
|
|
return int64(1)
|
|
}
|
|
/* If the next character is a digit, this is a floating point
|
|
** number that begins with ".". Fall thru into the next case */
|
|
fallthrough
|
|
case int32(CC_DIGIT):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_INTEGER)
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('0') && (libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) == int32('x') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) == int32('X')) && libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + 2))])&int32(0x08) != 0 {
|
|
i = int64(3)
|
|
for {
|
|
if !(int32(1) != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x08) == 0 {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) == int32('_') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_QNUMBER)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
goto _11
|
|
_11:
|
|
;
|
|
i = i + 1
|
|
}
|
|
} else {
|
|
i = 0
|
|
for {
|
|
if !(int32(1) != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x04) == 0 {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) == int32('_') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_QNUMBER)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
goto _12
|
|
_12:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) == int32('.') {
|
|
if **(**int32)(__ccgo_up(tokenType)) == int32(TK_INTEGER) {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_FLOAT)
|
|
}
|
|
i = i + 1
|
|
for {
|
|
if !(int32(1) != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x04) == 0 {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) == int32('_') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_QNUMBER)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
goto _13
|
|
_13:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
if (libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) == int32('e') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) == int32('E')) && (libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i+int64(1))))])&int32(0x04) != 0 || (libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i+int64(1))))) == int32('+') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i+int64(1))))) == int32('-')) && libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i+int64(2))))])&int32(0x04) != 0) {
|
|
if **(**int32)(__ccgo_up(tokenType)) == int32(TK_INTEGER) {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_FLOAT)
|
|
}
|
|
i = i + int64(2)
|
|
for {
|
|
if !(int32(1) != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x04) == 0 {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) == int32('_') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_QNUMBER)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
goto _14
|
|
_14:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
}
|
|
for libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x46) != 0 {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ILLEGAL)
|
|
i = i + 1
|
|
}
|
|
return i
|
|
case int32(CC_QUOTE2):
|
|
i = int64(1)
|
|
c = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z)))
|
|
for {
|
|
if v6 = c != int32(']'); v6 {
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i))))
|
|
c = v3
|
|
}
|
|
if !(v6 && v3 != 0) {
|
|
break
|
|
}
|
|
goto _15
|
|
_15:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if c == int32(']') {
|
|
v3 = int32(TK_ID)
|
|
} else {
|
|
v3 = int32(TK_ILLEGAL)
|
|
}
|
|
**(**int32)(__ccgo_up(tokenType)) = v3
|
|
return i
|
|
case int32(CC_VARNUM):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_VARIABLE)
|
|
i = int64(1)
|
|
for {
|
|
if !(libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x04) != 0) {
|
|
break
|
|
}
|
|
goto _19
|
|
_19:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return i
|
|
case int32(CC_DOLLAR):
|
|
fallthrough
|
|
case int32(CC_VARALPHA):
|
|
n = 0
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_VARIABLE)
|
|
i = int64(1)
|
|
for {
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i))))
|
|
c = v3
|
|
if !(v3 != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[libc.Uint8FromInt32(c)])&int32(0x46) != 0 {
|
|
n = n + 1
|
|
} else {
|
|
if c == int32('(') && n > 0 {
|
|
for {
|
|
i = i + 1
|
|
goto _23
|
|
_23:
|
|
;
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i))))
|
|
c = v3
|
|
if !(v3 != 0 && !(libc.Int32FromUint8(_sqlite3CtypeMap[libc.Uint8FromInt32(c)])&libc.Int32FromInt32(0x01) != 0) && c != int32(')')) {
|
|
break
|
|
}
|
|
}
|
|
if c == int32(')') {
|
|
i = i + 1
|
|
} else {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ILLEGAL)
|
|
}
|
|
break
|
|
} else {
|
|
if c == int32(':') && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i+int64(1))))) == int32(':') {
|
|
i = i + 1
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
goto _20
|
|
_20:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if n == 0 {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ILLEGAL)
|
|
}
|
|
return i
|
|
case int32(CC_KYWD0):
|
|
if libc.Int32FromUint8(_aiClass[**(**uint8)(__ccgo_up(z + 1))]) > int32(CC_KYWD) {
|
|
i = int64(1)
|
|
break
|
|
}
|
|
i = int64(2)
|
|
for {
|
|
if !(libc.Int32FromUint8(_aiClass[**(**uint8)(__ccgo_up(z + uintptr(i)))]) <= int32(CC_KYWD)) {
|
|
break
|
|
}
|
|
goto _24
|
|
_24:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x46) != 0 {
|
|
/* This token started out using characters that can appear in keywords,
|
|
** but z[i] is a character not allowed within keywords, so this must
|
|
** be an identifier instead */
|
|
i = i + 1
|
|
break
|
|
}
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ID)
|
|
return _keywordCode(tls, z, i, tokenType)
|
|
case CC_X:
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) == int32('\'') {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_BLOB)
|
|
i = int64(2)
|
|
for {
|
|
if !(libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x08) != 0) {
|
|
break
|
|
}
|
|
goto _25
|
|
_25:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) != int32('\'') || i%int64(2) != 0 {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ILLEGAL)
|
|
for **(**uint8)(__ccgo_up(z + uintptr(i))) != 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(i)))) != int32('\'') {
|
|
i = i + 1
|
|
}
|
|
}
|
|
if **(**uint8)(__ccgo_up(z + uintptr(i))) != 0 {
|
|
i = i + 1
|
|
}
|
|
return i
|
|
}
|
|
/* If it is not a BLOB literal, then it must be an ID, since no
|
|
** SQL keywords start with the letter 'x'. Fall through */
|
|
fallthrough
|
|
case int32(CC_KYWD):
|
|
fallthrough
|
|
case int32(CC_ID):
|
|
i = int64(1)
|
|
case int32(CC_BOM):
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 1))) == int32(0xbb) && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + 2))) == int32(0xbf) {
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_SPACE)
|
|
return int64(3)
|
|
}
|
|
i = int64(1)
|
|
case int32(CC_NUL):
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ILLEGAL)
|
|
return 0
|
|
default:
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ILLEGAL)
|
|
return int64(1)
|
|
}
|
|
for libc.Int32FromUint8(_sqlite3CtypeMap[**(**uint8)(__ccgo_up(z + uintptr(i)))])&int32(0x46) != 0 {
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(tokenType)) = int32(TK_ID)
|
|
return i
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read a 64-bit variable-length integer from memory starting at p[0].
|
|
// ** Return the number of bytes read. The value is stored in *v.
|
|
// */
|
|
func _sqlite3GetVarint(tls *libc.TLS, p uintptr, v uintptr) (r Tu8) {
|
|
var a, b, s Tu32
|
|
_, _, _ = a, b, s
|
|
if int32(**(**int8)(__ccgo_up(p))) >= 0 {
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(**(**uint8)(__ccgo_up(p)))
|
|
return uint8(1)
|
|
}
|
|
if int32(**(**int8)(__ccgo_up(p + 1))) >= 0 {
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(libc.Uint32FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(p)))&libc.Int32FromInt32(0x7f))<<libc.Int32FromInt32(7) | uint32(**(**uint8)(__ccgo_up(p + 1))))
|
|
return uint8(2)
|
|
}
|
|
/* Verify that constants are precomputed correctly */
|
|
a = uint32(**(**uint8)(__ccgo_up(p))) << int32(14)
|
|
b = uint32(**(**uint8)(__ccgo_up(p + 1)))
|
|
p = p + uintptr(2)
|
|
a = a | uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* a: p0<<14 | p2 (unmasked) */
|
|
if !(a&libc.Uint32FromInt32(0x80) != 0) {
|
|
a = a & uint32(SLOT_2_0)
|
|
b = b & uint32(0x7f)
|
|
b = b << int32(7)
|
|
a = a | b
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(a)
|
|
return uint8(3)
|
|
}
|
|
/* CSE1 from below */
|
|
a = a & uint32(SLOT_2_0)
|
|
p = p + 1
|
|
b = b << int32(14)
|
|
b = b | uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* b: p1<<14 | p3 (unmasked) */
|
|
if !(b&libc.Uint32FromInt32(0x80) != 0) {
|
|
b = b & uint32(SLOT_2_0)
|
|
/* moved CSE1 up */
|
|
/* a &= (0x7f<<14)|(0x7f); */
|
|
a = a << int32(7)
|
|
a = a | b
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(a)
|
|
return uint8(4)
|
|
}
|
|
/* a: p0<<14 | p2 (masked) */
|
|
/* b: p1<<14 | p3 (unmasked) */
|
|
/* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
|
|
/* moved CSE1 up */
|
|
/* a &= (0x7f<<14)|(0x7f); */
|
|
b = b & uint32(SLOT_2_0)
|
|
s = a
|
|
/* s: p0<<14 | p2 (masked) */
|
|
p = p + 1
|
|
a = a << int32(14)
|
|
a = a | uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
|
|
if !(a&libc.Uint32FromInt32(0x80) != 0) {
|
|
/* we can skip these cause they were (effectively) done above
|
|
** while calculating s */
|
|
/* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
|
|
/* b &= (0x7f<<14)|(0x7f); */
|
|
b = b << int32(7)
|
|
a = a | b
|
|
s = s >> int32(18)
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(s)<<int32(32) | uint64(a)
|
|
return uint8(5)
|
|
}
|
|
/* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
|
|
s = s << int32(7)
|
|
s = s | b
|
|
/* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
|
|
p = p + 1
|
|
b = b << int32(14)
|
|
b = b | uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* b: p1<<28 | p3<<14 | p5 (unmasked) */
|
|
if !(b&libc.Uint32FromInt32(0x80) != 0) {
|
|
/* we can skip this cause it was (effectively) done above in calc'ing s */
|
|
/* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
|
|
a = a & uint32(SLOT_2_0)
|
|
a = a << int32(7)
|
|
a = a | b
|
|
s = s >> int32(18)
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(s)<<int32(32) | uint64(a)
|
|
return uint8(6)
|
|
}
|
|
p = p + 1
|
|
a = a << int32(14)
|
|
a = a | uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* a: p2<<28 | p4<<14 | p6 (unmasked) */
|
|
if !(a&libc.Uint32FromInt32(0x80) != 0) {
|
|
a = a & uint32(SLOT_4_2_0)
|
|
b = b & uint32(SLOT_2_0)
|
|
b = b << int32(7)
|
|
a = a | b
|
|
s = s >> int32(11)
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(s)<<int32(32) | uint64(a)
|
|
return uint8(7)
|
|
}
|
|
/* CSE2 from below */
|
|
a = a & uint32(SLOT_2_0)
|
|
p = p + 1
|
|
b = b << int32(14)
|
|
b = b | uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* b: p3<<28 | p5<<14 | p7 (unmasked) */
|
|
if !(b&libc.Uint32FromInt32(0x80) != 0) {
|
|
b = b & uint32(SLOT_4_2_0)
|
|
/* moved CSE2 up */
|
|
/* a &= (0x7f<<14)|(0x7f); */
|
|
a = a << int32(7)
|
|
a = a | b
|
|
s = s >> int32(4)
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(s)<<int32(32) | uint64(a)
|
|
return uint8(8)
|
|
}
|
|
p = p + 1
|
|
a = a << int32(15)
|
|
a = a | uint32(**(**uint8)(__ccgo_up(p)))
|
|
/* a: p4<<29 | p6<<15 | p8 (unmasked) */
|
|
/* moved CSE2 up */
|
|
/* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
|
|
b = b & uint32(SLOT_2_0)
|
|
b = b << int32(8)
|
|
a = a | b
|
|
s = s << int32(4)
|
|
b = uint32(**(**uint8)(__ccgo_up(p + uintptr(-libc.Int32FromInt32(4)))))
|
|
b = b & uint32(0x7f)
|
|
b = b >> int32(3)
|
|
s = s | b
|
|
**(**Tu64)(__ccgo_up(v)) = uint64(s)<<int32(32) | uint64(a)
|
|
return uint8(9)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read a 32-bit variable-length integer from memory starting at p[0].
|
|
// ** Return the number of bytes read. The value is stored in *v.
|
|
// **
|
|
// ** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned
|
|
// ** integer, then set *v to 0xffffffff.
|
|
// **
|
|
// ** A MACRO version, getVarint32, is provided which inlines the
|
|
// ** single-byte case. All code should use the MACRO version as
|
|
// ** this function assumes the single-byte case has already been handled.
|
|
// */
|
|
func _sqlite3GetVarint32(tls *libc.TLS, p uintptr, v uintptr) (r Tu8) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var n Tu8
|
|
var _ /* v64 at bp+0 */ Tu64
|
|
_ = n
|
|
/* Assume that the single-byte case has already been handled by
|
|
** the getVarint32() macro */
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(p + 1)))&int32(0x80) == 0 {
|
|
/* This is the two-byte case */
|
|
**(**Tu32)(__ccgo_up(v)) = libc.Uint32FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(p)))&int32(0x7f)<<int32(7) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(p + 1))))
|
|
return uint8(2)
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(p + 2)))&int32(0x80) == 0 {
|
|
/* This is the three-byte case */
|
|
**(**Tu32)(__ccgo_up(v)) = libc.Uint32FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(p)))&int32(0x7f)<<int32(14) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(p + 1)))&int32(0x7f)<<int32(7) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(p + 2))))
|
|
return uint8(3)
|
|
}
|
|
/* four or more bytes */
|
|
n = _sqlite3GetVarint(tls, p, bp)
|
|
if **(**Tu64)(__ccgo_up(bp))&(libc.Uint64FromInt32(1)<<libc.Int32FromInt32(32)-libc.Uint64FromInt32(1)) != **(**Tu64)(__ccgo_up(bp)) {
|
|
**(**Tu32)(__ccgo_up(v)) = uint32(0xffffffff)
|
|
} else {
|
|
**(**Tu32)(__ccgo_up(v)) = uint32(**(**Tu64)(__ccgo_up(bp)))
|
|
}
|
|
return n
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Translate a single byte of Hex into an integer.
|
|
// ** This routine only works if h really is a valid hexadecimal
|
|
// ** character: 0..9a..fA..F
|
|
// */
|
|
func _sqlite3HexToInt(tls *libc.TLS, h int32) (r Tu8) {
|
|
h = h + int32(9)*(int32(1)&(h>>int32(6)))
|
|
return libc.Uint8FromInt32(h & libc.Int32FromInt32(0xf))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Make the IdChar function accessible from ctime.c and alter.c */
|
|
func _sqlite3IsIdChar(tls *libc.TLS, c Tu8) (r int32) {
|
|
return libc.BoolInt32(libc.Int32FromUint8(_sqlite3CtypeMap[c])&int32(0x46) != 0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function returns the collation sequence for database native text
|
|
// ** encoding identified by the string zName.
|
|
// **
|
|
// ** If the requested collation sequence is not available, or not available
|
|
// ** in the database native encoding, the collation factory is invoked to
|
|
// ** request it. If the collation factory does not supply such a sequence,
|
|
// ** and the sequence is available in another text encoding, then that is
|
|
// ** returned instead.
|
|
// **
|
|
// ** If no versions of the requested collations sequence are available, or
|
|
// ** another error occurs, NULL is returned and an error message written into
|
|
// ** pParse.
|
|
// **
|
|
// ** This routine is a wrapper around sqlite3FindCollSeq(). This routine
|
|
// ** invokes the collation factory if the named collation cannot be found
|
|
// ** and generates an error message.
|
|
// **
|
|
// ** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq()
|
|
// */
|
|
func _sqlite3LocateCollSeq(tls *libc.TLS, pParse uintptr, zName uintptr) (r uintptr) {
|
|
var db, pColl uintptr
|
|
var enc, initbusy Tu8
|
|
_, _, _, _ = db, enc, initbusy, pColl
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
enc = (*Tsqlite3)(unsafe.Pointer(db)).Fenc
|
|
initbusy = (*Tsqlite3)(unsafe.Pointer(db)).Finit1.Fbusy
|
|
pColl = _sqlite3FindCollSeq(tls, db, enc, zName, libc.Int32FromUint8(initbusy))
|
|
if !(initbusy != 0) && (!(pColl != 0) || !((*TCollSeq)(unsafe.Pointer(pColl)).FxCmp != 0)) {
|
|
pColl = _sqlite3GetCollSeq(tls, pParse, enc, pColl, zName)
|
|
}
|
|
return pColl
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find (an approximate) sum of two LogEst values. This computation is
|
|
// ** not a simple "+" operator because LogEst is stored as a logarithmic
|
|
// ** value.
|
|
// **
|
|
// */
|
|
func _sqlite3LogEstAdd(tls *libc.TLS, a TLogEst, b TLogEst) (r TLogEst) {
|
|
if int32(a) >= int32(b) {
|
|
if int32(a) > int32(b)+int32(49) {
|
|
return a
|
|
}
|
|
if int32(a) > int32(b)+int32(31) {
|
|
return int16(int32(a) + int32(1))
|
|
}
|
|
return int16(int32(a) + libc.Int32FromUint8(_x[int32(a)-int32(b)]))
|
|
} else {
|
|
if int32(b) > int32(a)+int32(49) {
|
|
return b
|
|
}
|
|
if int32(b) > int32(a)+int32(31) {
|
|
return int16(int32(b) + int32(1))
|
|
}
|
|
return int16(int32(b) + libc.Int32FromUint8(_x[int32(b)-int32(a)]))
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert a LogEst into an integer.
|
|
// */
|
|
func _sqlite3LogEstToInt(tls *libc.TLS, x TLogEst) (r Tu64) {
|
|
var n Tu64
|
|
var v1 uint64
|
|
_, _ = n, v1
|
|
n = libc.Uint64FromInt32(int32(x) % int32(10))
|
|
x = int16(int32(x) / libc.Int32FromInt32(10))
|
|
if n >= uint64(5) {
|
|
n = n - uint64(2)
|
|
} else {
|
|
if n >= uint64(1) {
|
|
n = n - uint64(1)
|
|
}
|
|
}
|
|
if int32(x) > int32(60) {
|
|
return libc.Uint64FromInt64(libc.Int64FromUint32(0xffffffff) | libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32))
|
|
}
|
|
if int32(x) >= int32(3) {
|
|
v1 = (n + uint64(8)) << (int32(x) - int32(3))
|
|
} else {
|
|
v1 = (n + uint64(8)) >> (int32(3) - int32(x))
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Count the number of slots of lookaside memory that are outstanding
|
|
// */
|
|
func _sqlite3LookasideUsed(tls *libc.TLS, db uintptr, pHighwater uintptr) (r int32) {
|
|
var nFree, nInit Tu32
|
|
_, _ = nFree, nInit
|
|
nInit = _countLookasideSlots(tls, (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpInit)
|
|
nFree = _countLookasideSlots(tls, (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpFree)
|
|
nInit = nInit + _countLookasideSlots(tls, (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallInit)
|
|
nFree = nFree + _countLookasideSlots(tls, (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallFree)
|
|
if pHighwater != 0 {
|
|
**(**int32)(__ccgo_up(pHighwater)) = libc.Int32FromUint32((*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FnSlot - nInit)
|
|
}
|
|
return libc.Int32FromUint32((*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FnSlot - (nInit + nFree))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate memory. This routine is like sqlite3_malloc() except that it
|
|
// ** assumes the memory subsystem has already been initialized.
|
|
// */
|
|
func _sqlite3Malloc(tls *libc.TLS, n Tu64) (r uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var _ /* p at bp+0 */ uintptr
|
|
if n == uint64(0) || n > uint64(SQLITE_MAX_ALLOCATION_SIZE) {
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
} else {
|
|
if _sqlite3Config.FbMemstat != 0 {
|
|
Xsqlite3_mutex_enter(tls, _mem0.Fmutex)
|
|
_mallocWithAlarm(tls, libc.Int32FromUint64(n), bp)
|
|
Xsqlite3_mutex_leave(tls, _mem0.Fmutex)
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(bp)) = (*(*func(*libc.TLS, int32) uintptr)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fm.FxMalloc})))(tls, libc.Int32FromUint64(n))
|
|
}
|
|
}
|
|
/* IMP: R-11148-40995 */
|
|
return **(**uintptr)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compare the values contained by the two memory cells, returning
|
|
// ** negative, zero or positive if pMem1 is less than, equal to, or greater
|
|
// ** than pMem2. Sorting order is NULL's first, followed by numbers (integers
|
|
// ** and reals) sorted numerically, followed by text ordered by the collating
|
|
// ** sequence pColl and finally blob's ordered by memcmp().
|
|
// **
|
|
// ** Two NULL values are considered equal by this function.
|
|
// */
|
|
func _sqlite3MemCompare(tls *libc.TLS, pMem1 uintptr, pMem2 uintptr, pColl uintptr) (r int32) {
|
|
var combined_flags, f1, f2 int32
|
|
_, _, _ = combined_flags, f1, f2
|
|
f1 = libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem1)).Fflags)
|
|
f2 = libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem2)).Fflags)
|
|
combined_flags = f1 | f2
|
|
/* If one value is NULL, it is less than the other. If both values
|
|
** are NULL, return 0.
|
|
*/
|
|
if combined_flags&int32(MEM_Null) != 0 {
|
|
return f2&int32(MEM_Null) - f1&int32(MEM_Null)
|
|
}
|
|
/* At least one of the two values is a number
|
|
*/
|
|
if combined_flags&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_Real)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
if f1&f2&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
if *(*Ti64)(unsafe.Pointer(pMem1)) < *(*Ti64)(unsafe.Pointer(pMem2)) {
|
|
return -int32(1)
|
|
}
|
|
if *(*Ti64)(unsafe.Pointer(pMem1)) > *(*Ti64)(unsafe.Pointer(pMem2)) {
|
|
return +libc.Int32FromInt32(1)
|
|
}
|
|
return 0
|
|
}
|
|
if f1&f2&int32(MEM_Real) != 0 {
|
|
if *(*float64)(unsafe.Pointer(pMem1)) < *(*float64)(unsafe.Pointer(pMem2)) {
|
|
return -int32(1)
|
|
}
|
|
if *(*float64)(unsafe.Pointer(pMem1)) > *(*float64)(unsafe.Pointer(pMem2)) {
|
|
return +libc.Int32FromInt32(1)
|
|
}
|
|
return 0
|
|
}
|
|
if f1&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
if f2&int32(MEM_Real) != 0 {
|
|
return _sqlite3IntFloatCompare(tls, *(*Ti64)(unsafe.Pointer(pMem1)), *(*float64)(unsafe.Pointer(pMem2)))
|
|
} else {
|
|
if f2&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
if *(*Ti64)(unsafe.Pointer(pMem1)) < *(*Ti64)(unsafe.Pointer(pMem2)) {
|
|
return -int32(1)
|
|
}
|
|
if *(*Ti64)(unsafe.Pointer(pMem1)) > *(*Ti64)(unsafe.Pointer(pMem2)) {
|
|
return +libc.Int32FromInt32(1)
|
|
}
|
|
return 0
|
|
} else {
|
|
return -int32(1)
|
|
}
|
|
}
|
|
}
|
|
if f1&int32(MEM_Real) != 0 {
|
|
if f2&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
return -_sqlite3IntFloatCompare(tls, *(*Ti64)(unsafe.Pointer(pMem2)), *(*float64)(unsafe.Pointer(pMem1)))
|
|
} else {
|
|
return -int32(1)
|
|
}
|
|
}
|
|
return +libc.Int32FromInt32(1)
|
|
}
|
|
/* If one value is a string and the other is a blob, the string is less.
|
|
** If both are strings, compare using the collating functions.
|
|
*/
|
|
if combined_flags&int32(MEM_Str) != 0 {
|
|
if f1&int32(MEM_Str) == 0 {
|
|
return int32(1)
|
|
}
|
|
if f2&int32(MEM_Str) == 0 {
|
|
return -int32(1)
|
|
}
|
|
/* The collation sequence must be defined at this point, even if
|
|
** the user deletes the collation sequence after the vdbe program is
|
|
** compiled (this was not always the case).
|
|
*/
|
|
if pColl != 0 {
|
|
return _vdbeCompareMemString(tls, pMem1, pMem2, pColl, uintptr(0))
|
|
}
|
|
/* If a NULL pointer was passed as the collate function, fall through
|
|
** to the blob case and use memcmp(). */
|
|
}
|
|
/* Both values must be blobs. Compare using memcmp(). */
|
|
return _sqlite3BlobCompare(tls, pMem1, pMem2)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Invoke sqlite3AtoF() on the text value of pMem. Write the
|
|
// ** translation of the text input into *pValue.
|
|
// **
|
|
// ** The caller must ensure that pMem->db!=0 and that pMem is in
|
|
// ** mode MEM_Str or MEM_Blob.
|
|
// **
|
|
// ** Result code invariants:
|
|
// **
|
|
// ** rc==0 => ERROR: Input string not well-formed, or OOM
|
|
// ** rc<0 => Some prefix of the input is well-formed
|
|
// ** rc>0 => All of the input is well-formed
|
|
// ** (rc&2)==0 => The number is expressed as an integer, with no
|
|
// ** decimal point or eNNN suffix.
|
|
// */
|
|
func _sqlite3MemRealValueRC(tls *libc.TLS, pMem uintptr, pValue uintptr) (r int32) {
|
|
if (*TMem)(unsafe.Pointer(pMem)).Fz == uintptr(0) {
|
|
**(**float64)(__ccgo_up(pValue)) = float64(0)
|
|
return 0
|
|
} else {
|
|
if libc.Int32FromUint8((*TMem)(unsafe.Pointer(pMem)).Fenc) == int32(SQLITE_UTF8) && (libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Term) != 0 || _sqlite3VdbeMemZeroTerminateIfAble(tls, pMem) != 0) {
|
|
return _sqlite3AtoF(tls, (*TMem)(unsafe.Pointer(pMem)).Fz, pValue)
|
|
} else {
|
|
if (*TMem)(unsafe.Pointer(pMem)).Fn == 0 {
|
|
**(**float64)(__ccgo_up(pValue)) = float64(0)
|
|
return 0
|
|
} else {
|
|
return _sqlite3MemRealValueRCSlowPath(tls, pMem, pValue)
|
|
}
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will
|
|
// **
|
|
// ** (1) acquire a lock for table pTab then
|
|
// ** (2) open pTab as cursor iCur.
|
|
// **
|
|
// ** If pTab is a WITHOUT ROWID table, then it is the PRIMARY KEY index
|
|
// ** for that table that is actually opened.
|
|
// */
|
|
func _sqlite3OpenTable(tls *libc.TLS, pParse uintptr, iCur int32, iDb int32, pTab uintptr, opcode int32) {
|
|
var pPk, v uintptr
|
|
var v1 int32
|
|
_, _, _ = pPk, v, v1
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
if !((*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FnoSharedCache != 0) {
|
|
if opcode == int32(OP_OpenWrite) {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
_sqlite3TableLock(tls, pParse, iDb, (*TTable)(unsafe.Pointer(pTab)).Ftnum, libc.Uint8FromInt32(v1), (*TTable)(unsafe.Pointer(pTab)).FzName)
|
|
}
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0) {
|
|
_sqlite3VdbeAddOp4Int(tls, v, opcode, iCur, libc.Int32FromUint32((*TTable)(unsafe.Pointer(pTab)).Ftnum), iDb, int32((*TTable)(unsafe.Pointer(pTab)).FnNVCol))
|
|
} else {
|
|
pPk = _sqlite3PrimaryKeyIndex(tls, pTab)
|
|
_sqlite3VdbeAddOp3(tls, v, opcode, iCur, libc.Int32FromUint32((*TIndex)(unsafe.Pointer(pPk)).Ftnum), iDb)
|
|
_sqlite3VdbeSetP4KeyInfo(tls, pParse, pPk)
|
|
}
|
|
}
|
|
|
|
func _sqlite3OsOpenMalloc(tls *libc.TLS, pVfs uintptr, zFile uintptr, ppFile uintptr, flags int32, pOutFlags uintptr) (r int32) {
|
|
var pFile uintptr
|
|
var rc int32
|
|
_, _ = pFile, rc
|
|
pFile = _sqlite3MallocZero(tls, libc.Uint64FromInt32((*Tsqlite3_vfs)(unsafe.Pointer(pVfs)).FszOsFile))
|
|
if pFile != 0 {
|
|
rc = _sqlite3OsOpen(tls, pVfs, zFile, pFile, flags, pOutFlags)
|
|
if rc != SQLITE_OK {
|
|
Xsqlite3_free(tls, pFile)
|
|
**(**uintptr)(__ccgo_up(ppFile)) = uintptr(0)
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(ppFile)) = pFile
|
|
}
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(ppFile)) = uintptr(0)
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Create a TK_IS or TK_ISNOT operator, perhaps optimized to
|
|
// ** TK_ISNULL or TK_NOTNULL or TK_TRUEFALSE. */
|
|
func _sqlite3PExprIs(tls *libc.TLS, pParse uintptr, op int32, pLeft uintptr, pRight uintptr) (r uintptr) {
|
|
var v1 int32
|
|
_ = v1
|
|
if pRight != 0 && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pRight)).Fop) == int32(TK_NULL) {
|
|
_sqlite3ExprDeferredDelete(tls, pParse, pRight)
|
|
if op == int32(TK_IS) {
|
|
v1 = int32(TK_ISNULL)
|
|
} else {
|
|
v1 = int32(TK_NOTNULL)
|
|
}
|
|
return _sqlite3PExprIsNull(tls, pParse, v1, pLeft)
|
|
}
|
|
return _sqlite3PExpr(tls, pParse, op, pLeft, pRight)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Create a TK_ISNULL or TK_NOTNULL expression, perhaps optimized to
|
|
// ** to TK_TRUEFALSE, if possible */
|
|
func _sqlite3PExprIsNull(tls *libc.TLS, pParse uintptr, op int32, pLeft uintptr) (r uintptr) {
|
|
var p uintptr
|
|
_ = p
|
|
p = pLeft
|
|
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
|
|
}
|
|
switch libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) {
|
|
case int32(TK_INTEGER):
|
|
fallthrough
|
|
case int32(TK_STRING):
|
|
fallthrough
|
|
case int32(TK_FLOAT):
|
|
fallthrough
|
|
case int32(TK_BLOB):
|
|
_sqlite3ExprDeferredDelete(tls, pParse, pLeft)
|
|
return _sqlite3ExprInt32(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, libc.BoolInt32(op == int32(TK_NOTNULL)))
|
|
default:
|
|
break
|
|
}
|
|
return _sqlite3PExpr(tls, pParse, op, pLeft, uintptr(0))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Begin a write-transaction on the specified pager object. If a
|
|
// ** write-transaction has already been opened, this function is a no-op.
|
|
// **
|
|
// ** If the exFlag argument is false, then acquire at least a RESERVED
|
|
// ** lock on the database file. If exFlag is true, then acquire at least
|
|
// ** an EXCLUSIVE lock. If such a lock is already held, no locking
|
|
// ** functions need be called.
|
|
// **
|
|
// ** If the subjInMemory argument is non-zero, then any sub-journal opened
|
|
// ** within this transaction will be opened as an in-memory file. This
|
|
// ** has no effect if the sub-journal is already opened (as it may be when
|
|
// ** running in exclusive mode) or if the transaction does not require a
|
|
// ** sub-journal. If the subjInMemory argument is zero, then any required
|
|
// ** sub-journal is implemented in-memory if pPager is an in-memory database,
|
|
// ** or using a temporary file otherwise.
|
|
// */
|
|
func _sqlite3PagerBegin(tls *libc.TLS, pPager uintptr, exFlag int32, subjInMemory int32) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
rc = SQLITE_OK
|
|
if (*TPager)(unsafe.Pointer(pPager)).FerrCode != 0 {
|
|
return (*TPager)(unsafe.Pointer(pPager)).FerrCode
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FsubjInMemory = libc.Uint8FromInt32(subjInMemory)
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_READER) {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
|
|
/* If the pager is configured to use locking_mode=exclusive, and an
|
|
** exclusive lock on the database is not already held, obtain it now.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0 && _sqlite3WalExclusiveMode(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal, -int32(1)) != 0 {
|
|
rc = _pagerLockDb(tls, pPager, int32(EXCLUSIVE_LOCK))
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
_sqlite3WalExclusiveMode(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal, int32(1))
|
|
}
|
|
/* Grab the write lock on the log file. If successful, upgrade to
|
|
** PAGER_RESERVED state. Otherwise, return an error code to the caller.
|
|
** The busy-handler is not invoked if another connection already
|
|
** holds the write-lock. If possible, the upper layer will call it.
|
|
*/
|
|
rc = _sqlite3WalBeginWriteTransaction(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal)
|
|
} else {
|
|
/* Obtain a RESERVED lock on the database file. If the exFlag parameter
|
|
** is true, then immediately upgrade this to an EXCLUSIVE lock. The
|
|
** busy-handler callback can be used when upgrading to the EXCLUSIVE
|
|
** lock, but not when obtaining the RESERVED lock.
|
|
*/
|
|
rc = _pagerLockDb(tls, pPager, int32(RESERVED_LOCK))
|
|
if rc == SQLITE_OK && exFlag != 0 {
|
|
rc = _pager_wait_on_lock(tls, pPager, int32(EXCLUSIVE_LOCK))
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
/* Change to WRITER_LOCKED state.
|
|
**
|
|
** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD
|
|
** when it has an open transaction, but never to DBMOD or FINISHED.
|
|
** This is because in those states the code to roll back savepoint
|
|
** transactions may copy data from the sub-journal into the database
|
|
** file as well as into the page cache. Which would be incorrect in
|
|
** WAL mode.
|
|
*/
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_WRITER_LOCKED)
|
|
(*TPager)(unsafe.Pointer(pPager)).FdbHintSize = (*TPager)(unsafe.Pointer(pPager)).FdbSize
|
|
(*TPager)(unsafe.Pointer(pPager)).FdbFileSize = (*TPager)(unsafe.Pointer(pPager)).FdbSize
|
|
(*TPager)(unsafe.Pointer(pPager)).FdbOrigSize = (*TPager)(unsafe.Pointer(pPager)).FdbSize
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = 0
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Unless this is an in-memory or temporary database, clear the pager cache.
|
|
// */
|
|
func _sqlite3PagerClearCache(tls *libc.TLS, pPager uintptr) {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FtempFile) == 0 {
|
|
_pager_reset(tls, pPager)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Shutdown the page cache. Free all memory and close all files.
|
|
// **
|
|
// ** If a transaction was in progress when this routine is called, that
|
|
// ** transaction is rolled back. All outstanding pages are invalidated
|
|
// ** and their memory is freed. Any attempt to use a page associated
|
|
// ** with this page cache after this function returns will likely
|
|
// ** result in a coredump.
|
|
// **
|
|
// ** This function always succeeds. If a transaction is active an attempt
|
|
// ** is made to roll it back. If an error occurs during the rollback
|
|
// ** a hot journal may be left in the filesystem but no error is returned
|
|
// ** to the caller.
|
|
// */
|
|
func _sqlite3PagerClose(tls *libc.TLS, pPager uintptr, db uintptr) (r int32) {
|
|
var a, pTmp uintptr
|
|
_, _ = a, pTmp
|
|
pTmp = (*TPager)(unsafe.Pointer(pPager)).FpTmpSpace
|
|
_sqlite3BeginBenignMalloc(tls)
|
|
_pagerFreeMapHdrs(tls, pPager)
|
|
/* pPager->errCode = 0; */
|
|
(*TPager)(unsafe.Pointer(pPager)).FexclusiveMode = uint8(0)
|
|
a = uintptr(0)
|
|
if db != 0 && uint64(0) == (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_NoCkptOnClose) && SQLITE_OK == _databaseIsUnmoved(tls, pPager) {
|
|
a = pTmp
|
|
}
|
|
_sqlite3WalClose(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal, db, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FwalSyncFlags), int32((*TPager)(unsafe.Pointer(pPager)).FpageSize), a)
|
|
(*TPager)(unsafe.Pointer(pPager)).FpWal = uintptr(0)
|
|
_pager_reset(tls, pPager)
|
|
if (*TPager)(unsafe.Pointer(pPager)).FmemDb != 0 {
|
|
_pager_unlock(tls, pPager)
|
|
} else {
|
|
/* If it is open, sync the journal file before calling UnlockAndRollback.
|
|
** If this is not done, then an unsynced portion of the open journal
|
|
** file may be played back into the database. If a power failure occurs
|
|
** while this is happening, the database could become corrupt.
|
|
**
|
|
** If an error occurs while trying to sync the journal, shift the pager
|
|
** into the ERROR state. This causes UnlockAndRollback to unlock the
|
|
** database and close the journal file without attempting to roll it
|
|
** back or finalize it. The next database user will have to do hot-journal
|
|
** rollback before accessing the database file.
|
|
*/
|
|
if (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != uintptr(0) {
|
|
_pager_error(tls, pPager, _pagerSyncHotJournal(tls, pPager))
|
|
}
|
|
_pagerUnlockAndRollback(tls, pPager)
|
|
}
|
|
_sqlite3EndBenignMalloc(tls)
|
|
_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
|
|
_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd)
|
|
_sqlite3PageFree(tls, pTmp)
|
|
_sqlite3PcacheClose(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache)
|
|
Xsqlite3_free(tls, pPager)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called to close the connection to the log file prior
|
|
// ** to switching from WAL to rollback mode.
|
|
// **
|
|
// ** Before closing the log file, this function attempts to take an
|
|
// ** EXCLUSIVE lock on the database file. If this cannot be obtained, an
|
|
// ** error (SQLITE_BUSY) is returned and the log connection is not closed.
|
|
// ** If successful, the EXCLUSIVE lock is not released before returning.
|
|
// */
|
|
func _sqlite3PagerCloseWal(tls *libc.TLS, pPager uintptr, db uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc int32
|
|
var _ /* logexists at bp+0 */ int32
|
|
_ = rc
|
|
rc = SQLITE_OK
|
|
/* If the log file is not already open, but does exist in the file-system,
|
|
** it may need to be checkpointed before the connection can switch to
|
|
** rollback mode. Open it now so this can happen.
|
|
*/
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FpWal != 0) {
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
rc = _pagerLockDb(tls, pPager, int32(SHARED_LOCK))
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3OsAccess(tls, (*TPager)(unsafe.Pointer(pPager)).FpVfs, (*TPager)(unsafe.Pointer(pPager)).FzWal, SQLITE_ACCESS_EXISTS, bp)
|
|
}
|
|
if rc == SQLITE_OK && **(**int32)(__ccgo_up(bp)) != 0 {
|
|
rc = _pagerOpenWal(tls, pPager)
|
|
}
|
|
}
|
|
/* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
|
|
** the database file, the log and log-summary files will be deleted.
|
|
*/
|
|
if rc == SQLITE_OK && (*TPager)(unsafe.Pointer(pPager)).FpWal != 0 {
|
|
rc = _pagerExclusiveLock(tls, pPager)
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3WalClose(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal, db, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FwalSyncFlags), int32((*TPager)(unsafe.Pointer(pPager)).FpageSize), (*TPager)(unsafe.Pointer(pPager)).FpTmpSpace)
|
|
(*TPager)(unsafe.Pointer(pPager)).FpWal = uintptr(0)
|
|
_pagerFixMaplimit(tls, pPager)
|
|
if rc != 0 && !((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0) {
|
|
_pagerUnlockDb(tls, pPager, int32(SHARED_LOCK))
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Sync the database file for the pager pPager. zSuper points to the name
|
|
// ** of a super-journal file that should be written into the individual
|
|
// ** journal file. zSuper may be NULL, which is interpreted as no
|
|
// ** super-journal (a single database transaction).
|
|
// **
|
|
// ** This routine ensures that:
|
|
// **
|
|
// ** * The database file change-counter is updated,
|
|
// ** * the journal is synced (unless the atomic-write optimization is used),
|
|
// ** * all dirty pages are written to the database file,
|
|
// ** * the database file is truncated (if required), and
|
|
// ** * the database file synced.
|
|
// **
|
|
// ** The only thing that remains to commit the transaction is to finalize
|
|
// ** (delete, truncate or zero the first part of) the journal file (or
|
|
// ** delete the super-journal file if specified).
|
|
// **
|
|
// ** Note that if zSuper==NULL, this does not overwrite a previous value
|
|
// ** passed to an sqlite3PagerCommitPhaseOne() call.
|
|
// **
|
|
// ** If the final parameter - noSync - is true, then the database file itself
|
|
// ** is not synced. The caller must call sqlite3PagerSync() directly to
|
|
// ** sync the database file before calling CommitPhaseTwo() to delete the
|
|
// ** journal file in this case.
|
|
// */
|
|
func _sqlite3PagerCommitPhaseOne(tls *libc.TLS, pPager uintptr, zSuper uintptr, noSync int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var nNew TPgno
|
|
var pList uintptr
|
|
var rc int32
|
|
var _ /* pPageOne at bp+0 */ uintptr
|
|
_, _, _ = nNew, pList, rc
|
|
rc = SQLITE_OK /* Return code */
|
|
/* If a prior error occurred, report that error again. */
|
|
if (*TPager)(unsafe.Pointer(pPager)).FerrCode != 0 {
|
|
return (*TPager)(unsafe.Pointer(pPager)).FerrCode
|
|
}
|
|
/* Provide the ability to easily simulate an I/O error during testing */
|
|
if _sqlite3FaultSim(tls, int32(400)) != 0 {
|
|
return int32(SQLITE_IOERR)
|
|
}
|
|
/* If no database changes have been made, return early. */
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) < int32(PAGER_WRITER_CACHEMOD) {
|
|
return SQLITE_OK
|
|
}
|
|
if 0 == _pagerFlushOnCommit(tls, pPager, int32(1)) {
|
|
/* If this is an in-memory db, or no pages have been written to, or this
|
|
** function has already been called, it is mostly a no-op. However, any
|
|
** backup in progress needs to be restarted. */
|
|
_sqlite3BackupRestart(tls, (*TPager)(unsafe.Pointer(pPager)).FpBackup)
|
|
} else {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
pList = _sqlite3PcacheDirtyList(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache)
|
|
if pList == uintptr(0) {
|
|
/* Must have at least one page for the WAL commit flag.
|
|
** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
|
|
rc = _sqlite3PagerGet(tls, pPager, uint32(1), bp, 0)
|
|
pList = **(**uintptr)(__ccgo_up(bp))
|
|
(*TPgHdr)(unsafe.Pointer(pList)).FpDirty = uintptr(0)
|
|
}
|
|
if pList != 0 {
|
|
rc = _pagerWalFrames(tls, pPager, pList, (*TPager)(unsafe.Pointer(pPager)).FdbSize, int32(1))
|
|
}
|
|
_sqlite3PagerUnref(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
if rc == SQLITE_OK {
|
|
_sqlite3PcacheCleanAll(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache)
|
|
}
|
|
} else {
|
|
/* The bBatch boolean is true if the batch-atomic-write commit method
|
|
** should be used. No rollback journal is created if batch-atomic-write
|
|
** is enabled.
|
|
*/
|
|
rc = _pager_incr_changecounter(tls, pPager, 0)
|
|
if rc != SQLITE_OK {
|
|
goto commit_phase_one_exit
|
|
}
|
|
/* Write the super-journal name into the journal file. If a
|
|
** super-journal file name has already been written to the journal file,
|
|
** or if zSuper is NULL (no super-journal), then this call is a no-op.
|
|
*/
|
|
rc = _writeSuperJournal(tls, pPager, zSuper)
|
|
if rc != SQLITE_OK {
|
|
goto commit_phase_one_exit
|
|
}
|
|
/* Sync the journal file and write all dirty pages to the database.
|
|
** If the atomic-update optimization is being used, this sync will not
|
|
** create the journal file or perform any real IO.
|
|
**
|
|
** Because the change-counter page was just modified, unless the
|
|
** atomic-update optimization is used it is almost certain that the
|
|
** journal requires a sync here. However, in locking_mode=exclusive
|
|
** on a system under memory pressure it is just possible that this is
|
|
** not the case. In this case it is likely enough that the redundant
|
|
** xSync() call will be changed to a no-op by the OS anyhow.
|
|
*/
|
|
rc = _syncJournal(tls, pPager, 0)
|
|
if rc != SQLITE_OK {
|
|
goto commit_phase_one_exit
|
|
}
|
|
pList = _sqlite3PcacheDirtyList(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache)
|
|
if true {
|
|
rc = _pager_write_pagelist(tls, pPager, pList)
|
|
}
|
|
if rc != SQLITE_OK {
|
|
goto commit_phase_one_exit
|
|
}
|
|
_sqlite3PcacheCleanAll(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache)
|
|
/* If the file on disk is smaller than the database image, use
|
|
** pager_truncate to grow the file here. This can happen if the database
|
|
** image was extended as part of the current transaction and then the
|
|
** last page in the db image moved to the free-list. In this case the
|
|
** last page is never written out to disk, leaving the database file
|
|
** undersized. Fix this now if it is the case. */
|
|
if (*TPager)(unsafe.Pointer(pPager)).FdbSize > (*TPager)(unsafe.Pointer(pPager)).FdbFileSize {
|
|
nNew = (*TPager)(unsafe.Pointer(pPager)).FdbSize - libc.BoolUint32((*TPager)(unsafe.Pointer(pPager)).FdbSize == (*TPager)(unsafe.Pointer(pPager)).FlckPgno)
|
|
rc = _pager_truncate(tls, pPager, nNew)
|
|
if rc != SQLITE_OK {
|
|
goto commit_phase_one_exit
|
|
}
|
|
}
|
|
/* Finally, sync the database file. */
|
|
if !(noSync != 0) {
|
|
rc = _sqlite3PagerSync(tls, pPager, zSuper)
|
|
}
|
|
}
|
|
}
|
|
goto commit_phase_one_exit
|
|
commit_phase_one_exit:
|
|
;
|
|
if rc == SQLITE_OK && !((*TPager)(unsafe.Pointer(pPager)).FpWal != libc.UintptrFromInt32(0)) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_WRITER_FINISHED)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** When this function is called, the database file has been completely
|
|
// ** updated to reflect the changes made by the current transaction and
|
|
// ** synced to disk. The journal file still exists in the file-system
|
|
// ** though, and if a failure occurs at this point it will eventually
|
|
// ** be used as a hot-journal and the current transaction rolled back.
|
|
// **
|
|
// ** This function finalizes the journal file, either by deleting,
|
|
// ** truncating or partially zeroing it, so that it cannot be used
|
|
// ** for hot-journal rollback. Once this is done the transaction is
|
|
// ** irrevocably committed.
|
|
// **
|
|
// ** If an error occurs, an IO error code is returned and the pager
|
|
// ** moves into the error state. Otherwise, SQLITE_OK is returned.
|
|
// */
|
|
func _sqlite3PagerCommitPhaseTwo(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
rc = SQLITE_OK /* Return code */
|
|
/* This routine should not be called if a prior error has occurred.
|
|
** But if (due to a coding error elsewhere in the system) it does get
|
|
** called, just return the same error code without doing anything. */
|
|
if (*TPager)(unsafe.Pointer(pPager)).FerrCode != 0 {
|
|
return (*TPager)(unsafe.Pointer(pPager)).FerrCode
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FiDataVersion = (*TPager)(unsafe.Pointer(pPager)).FiDataVersion + 1
|
|
/* An optimization. If the database was not actually modified during
|
|
** this transaction, the pager is running in exclusive-mode and is
|
|
** using persistent journals, then this function is a no-op.
|
|
**
|
|
** The start of the journal file currently contains a single journal
|
|
** header with the nRec field set to 0. If such a journal is used as
|
|
** a hot-journal during hot-journal rollback, 0 changes will be made
|
|
** to the database file. So there is no need to zero the journal
|
|
** header. Since the pager is in exclusive mode, there is no need
|
|
** to drop any locks either.
|
|
*/
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_WRITER_LOCKED) && (*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0 && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) == int32(PAGER_JOURNALMODE_PERSIST) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_READER)
|
|
return SQLITE_OK
|
|
}
|
|
rc = _pager_end_transaction(tls, pPager, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FsetSuper), int32(1))
|
|
return _pager_error(tls, pPager, rc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the current journal mode.
|
|
// */
|
|
func _sqlite3PagerGetJournalMode(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
return libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Get/set the locking-mode for this pager. Parameter eMode must be one
|
|
// ** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
|
|
// ** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
|
|
// ** the locking-mode is set to the value specified.
|
|
// **
|
|
// ** The returned value is either PAGER_LOCKINGMODE_NORMAL or
|
|
// ** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
|
|
// ** locking-mode.
|
|
// */
|
|
func _sqlite3PagerLockingMode(tls *libc.TLS, pPager uintptr, eMode int32) (r int32) {
|
|
if eMode >= 0 && !((*TPager)(unsafe.Pointer(pPager)).FtempFile != 0) && !(_sqlite3WalHeapMemory(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal) != 0) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FexclusiveMode = libc.Uint8FromInt32(eMode)
|
|
}
|
|
return libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return TRUE if the pager is in a state where it is OK to change the
|
|
// ** journalmode. Journalmode changes can only happen when the database
|
|
// ** is unmodified.
|
|
// */
|
|
func _sqlite3PagerOkToChangeJournalMode(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) >= int32(PAGER_WRITER_CACHEMOD) {
|
|
return 0
|
|
}
|
|
if (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != uintptr(0) && (*TPager)(unsafe.Pointer(pPager)).FjournalOff > 0 {
|
|
return 0
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function may only be called when a read-transaction is open on
|
|
// ** the pager. It returns the total number of pages in the database.
|
|
// **
|
|
// ** However, if the file is between 1 and <page-size> bytes in size, then
|
|
// ** this is considered a 1 page file.
|
|
// */
|
|
func _sqlite3PagerPagecount(tls *libc.TLS, pPager uintptr, pnPage uintptr) {
|
|
**(**int32)(__ccgo_up(pnPage)) = libc.Int32FromUint32((*TPager)(unsafe.Pointer(pPager)).FdbSize)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If a write transaction is open, then all changes made within the
|
|
// ** transaction are reverted and the current write-transaction is closed.
|
|
// ** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR
|
|
// ** state if an error occurs.
|
|
// **
|
|
// ** If the pager is already in PAGER_ERROR state when this function is called,
|
|
// ** it returns Pager.errCode immediately. No work is performed in this case.
|
|
// **
|
|
// ** Otherwise, in rollback mode, this function performs two functions:
|
|
// **
|
|
// ** 1) It rolls back the journal file, restoring all database file and
|
|
// ** in-memory cache pages to the state they were in when the transaction
|
|
// ** was opened, and
|
|
// **
|
|
// ** 2) It finalizes the journal file, so that it is not used for hot
|
|
// ** rollback at any point in the future.
|
|
// **
|
|
// ** Finalization of the journal file (task 2) is only performed if the
|
|
// ** rollback is successful.
|
|
// **
|
|
// ** In WAL mode, all cache-entries containing data modified within the
|
|
// ** current transaction are either expelled from the cache or reverted to
|
|
// ** their pre-transaction state by re-reading data from the database or
|
|
// ** WAL files. The WAL transaction is then closed.
|
|
// */
|
|
func _sqlite3PagerRollback(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
var eState, rc, rc2 int32
|
|
_, _, _ = eState, rc, rc2
|
|
rc = SQLITE_OK /* Return code */
|
|
/* PagerRollback() is a no-op if called in READER or OPEN state. If
|
|
** the pager is already in the ERROR state, the rollback is not
|
|
** attempted here. Instead, the error code is returned to the caller.
|
|
*/
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_ERROR) {
|
|
return (*TPager)(unsafe.Pointer(pPager)).FerrCode
|
|
}
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) <= int32(PAGER_READER) {
|
|
return SQLITE_OK
|
|
}
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
|
|
rc = _sqlite3PagerSavepoint(tls, pPager, int32(SAVEPOINT_ROLLBACK), -int32(1))
|
|
rc2 = _pager_end_transaction(tls, pPager, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FsetSuper), 0)
|
|
if rc == SQLITE_OK {
|
|
rc = rc2
|
|
}
|
|
} else {
|
|
if !((*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != libc.UintptrFromInt32(0)) || libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_WRITER_LOCKED) {
|
|
eState = libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState)
|
|
rc = _pager_end_transaction(tls, pPager, 0, 0)
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FmemDb != 0) && eState > int32(PAGER_WRITER_LOCKED) {
|
|
/* This can happen using journal_mode=off. Move the pager to the error
|
|
** state to indicate that the contents of the cache may not be trusted.
|
|
** Any active readers will get SQLITE_ABORT.
|
|
*/
|
|
(*TPager)(unsafe.Pointer(pPager)).FerrCode = int32(SQLITE_ABORT)
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_ERROR)
|
|
_setGetterMethod(tls, pPager)
|
|
return rc
|
|
}
|
|
} else {
|
|
rc = _pager_playback(tls, pPager, 0)
|
|
}
|
|
}
|
|
/* If an error occurs during a ROLLBACK, we can no longer trust the pager
|
|
** cache. So call pager_error() on the way out to make any error persistent.
|
|
*/
|
|
return _pager_error(tls, pPager, rc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the journal-mode for this pager. Parameter eMode must be one of:
|
|
// **
|
|
// ** PAGER_JOURNALMODE_DELETE
|
|
// ** PAGER_JOURNALMODE_TRUNCATE
|
|
// ** PAGER_JOURNALMODE_PERSIST
|
|
// ** PAGER_JOURNALMODE_OFF
|
|
// ** PAGER_JOURNALMODE_MEMORY
|
|
// ** PAGER_JOURNALMODE_WAL
|
|
// **
|
|
// ** The journalmode is set to the value specified if the change is allowed.
|
|
// ** The change may be disallowed for the following reasons:
|
|
// **
|
|
// ** * An in-memory database can only have its journal_mode set to _OFF
|
|
// ** or _MEMORY.
|
|
// **
|
|
// ** * Temporary databases cannot have _WAL journalmode.
|
|
// **
|
|
// ** The returned indicate the current (possibly updated) journal-mode.
|
|
// */
|
|
func _sqlite3PagerSetJournalMode(tls *libc.TLS, pPager uintptr, eMode int32) (r int32) {
|
|
var eOld Tu8
|
|
var rc, state int32
|
|
_, _, _ = eOld, rc, state
|
|
eOld = (*TPager)(unsafe.Pointer(pPager)).FjournalMode /* Prior journalmode */
|
|
/* The eMode parameter is always valid */
|
|
/* This routine is only called from the OP_JournalMode opcode, and
|
|
** the logic there will never allow a temporary file to be changed
|
|
** to WAL mode.
|
|
*/
|
|
/* Do allow the journalmode of an in-memory database to be set to
|
|
** anything other than MEMORY or OFF
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FmemDb != 0 {
|
|
if eMode != int32(PAGER_JOURNALMODE_MEMORY) && eMode != int32(PAGER_JOURNALMODE_OFF) {
|
|
eMode = libc.Int32FromUint8(eOld)
|
|
}
|
|
}
|
|
if eMode != libc.Int32FromUint8(eOld) {
|
|
/* Change the journal mode. */
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalMode = libc.Uint8FromInt32(eMode)
|
|
/* When transitioning from TRUNCATE or PERSIST to any other journal
|
|
** mode except WAL, unless the pager is in locking_mode=exclusive mode,
|
|
** delete the journal file.
|
|
*/
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0) && libc.Int32FromUint8(eOld)&int32(5) == int32(1) && eMode&int32(1) == 0 {
|
|
/* In this case we would like to delete the journal file. If it is
|
|
** not possible, then that is not a problem. Deleting the journal file
|
|
** here is an optimization only.
|
|
**
|
|
** Before deleting the journal file, obtain a RESERVED lock on the
|
|
** database file. This ensures that the journal file is not deleted
|
|
** while it is in use by some other client.
|
|
*/
|
|
_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeLock) >= int32(RESERVED_LOCK) {
|
|
_sqlite3OsDelete(tls, (*TPager)(unsafe.Pointer(pPager)).FpVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, 0)
|
|
} else {
|
|
rc = SQLITE_OK
|
|
state = libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState)
|
|
if state == PAGER_OPEN {
|
|
rc = _sqlite3PagerSharedLock(tls, pPager)
|
|
}
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_READER) {
|
|
rc = _pagerLockDb(tls, pPager, int32(RESERVED_LOCK))
|
|
}
|
|
if rc == SQLITE_OK {
|
|
_sqlite3OsDelete(tls, (*TPager)(unsafe.Pointer(pPager)).FpVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, 0)
|
|
}
|
|
if rc == SQLITE_OK && state == int32(PAGER_READER) {
|
|
_pagerUnlockDb(tls, pPager, int32(SHARED_LOCK))
|
|
} else {
|
|
if state == PAGER_OPEN {
|
|
_pager_unlock(tls, pPager)
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if eMode == int32(PAGER_JOURNALMODE_OFF) || eMode == int32(PAGER_JOURNALMODE_MEMORY) {
|
|
_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
|
|
}
|
|
}
|
|
}
|
|
/* Return the new journal mode */
|
|
return libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Sync the database file to disk. This is a no-op for in-memory databases
|
|
// ** or pages with the Pager.noSync flag set.
|
|
// **
|
|
// ** If successful, or if called on a pager for which it is a no-op, this
|
|
// ** function returns SQLITE_OK. Otherwise, an IO error code is returned.
|
|
// */
|
|
func _sqlite3PagerSync(tls *libc.TLS, pPager uintptr, zSuper uintptr) (r int32) {
|
|
var pArg uintptr
|
|
var rc int32
|
|
_, _ = pArg, rc
|
|
rc = SQLITE_OK
|
|
pArg = zSuper
|
|
rc = _sqlite3OsFileControl(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, int32(SQLITE_FCNTL_SYNC), pArg)
|
|
if rc == int32(SQLITE_NOTFOUND) {
|
|
rc = SQLITE_OK
|
|
}
|
|
if rc == SQLITE_OK && !((*TPager)(unsafe.Pointer(pPager)).FnoSync != 0) {
|
|
rc = _sqlite3OsSync(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FsyncFlags))
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Release a page reference.
|
|
// **
|
|
// ** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be used
|
|
// ** if we know that the page being released is not the last reference to page1.
|
|
// ** The btree layer always holds page1 open until the end, so these first
|
|
// ** two routines can be used to release any page other than BtShared.pPage1.
|
|
// ** The assert() at tag-20230419-2 proves that this constraint is always
|
|
// ** honored.
|
|
// **
|
|
// ** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine
|
|
// ** checks the total number of outstanding pages and if the number of
|
|
// ** pages reaches zero it drops the database lock.
|
|
// */
|
|
func _sqlite3PagerUnrefNotNull(tls *libc.TLS, pPg uintptr) {
|
|
if libc.Int32FromUint16((*TDbPage)(unsafe.Pointer(pPg)).Fflags)&int32(PGHDR_MMAP) != 0 {
|
|
/* Page1 is never memory mapped */
|
|
_pagerReleaseMapPage(tls, pPg)
|
|
} else {
|
|
_sqlite3PcacheRelease(tls, pPg)
|
|
}
|
|
/* Do not use this routine to release the last reference to page1 */
|
|
/* tag-20230419-2 */
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Mark a data page as writeable. This routine must be called before
|
|
// ** making changes to a page. The caller must check the return value
|
|
// ** of this function and be careful not to change any page data unless
|
|
// ** this routine returns SQLITE_OK.
|
|
// **
|
|
// ** The difference between this function and pager_write() is that this
|
|
// ** function also deals with the special case where 2 or more pages
|
|
// ** fit on a single disk sector. In this case all co-resident pages
|
|
// ** must have been written to the journal file before returning.
|
|
// **
|
|
// ** If an error occurs, SQLITE_NOMEM or an IO error code is returned
|
|
// ** as appropriate. Otherwise, SQLITE_OK.
|
|
// */
|
|
func _sqlite3PagerWrite(tls *libc.TLS, pPg uintptr) (r int32) {
|
|
var pPager uintptr
|
|
_ = pPager
|
|
pPager = (*TPgHdr)(unsafe.Pointer(pPg)).FpPager
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(pPg)).Fflags)&int32(PGHDR_WRITEABLE) != 0 && (*TPager)(unsafe.Pointer(pPager)).FdbSize >= (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FnSavepoint != 0 {
|
|
return _subjournalPageIfRequired(tls, pPg)
|
|
}
|
|
return SQLITE_OK
|
|
} else {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FerrCode != 0 {
|
|
return (*TPager)(unsafe.Pointer(pPager)).FerrCode
|
|
} else {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FsectorSize > libc.Uint32FromInt64((*TPager)(unsafe.Pointer(pPager)).FpageSize) {
|
|
return _pagerWriteLargeSector(tls, pPg)
|
|
} else {
|
|
return _pager_write(tls, pPg)
|
|
}
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
/*
|
|
** Return TRUE if the page given in the argument was previously passed
|
|
** to sqlite3PagerWrite(). In other words, return TRUE if it is ok
|
|
** to change the content of the page.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Free all memory allocations in the pParse object
|
|
// */
|
|
func _sqlite3ParseObjectReset(tls *libc.TLS, pParse uintptr) {
|
|
var db, pCleanup uintptr
|
|
var v1 int32
|
|
_, _, _ = db, pCleanup, v1
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if (*TParse)(unsafe.Pointer(pParse)).FaTableLock != 0 {
|
|
_sqlite3DbNNFreeNN(tls, db, (*TParse)(unsafe.Pointer(pParse)).FaTableLock)
|
|
}
|
|
for (*TParse)(unsafe.Pointer(pParse)).FpCleanup != 0 {
|
|
pCleanup = (*TParse)(unsafe.Pointer(pParse)).FpCleanup
|
|
(*TParse)(unsafe.Pointer(pParse)).FpCleanup = (*TParseCleanup)(unsafe.Pointer(pCleanup)).FpNext
|
|
(*(*func(*libc.TLS, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TParseCleanup)(unsafe.Pointer(pCleanup)).FxCleanup})))(tls, db, (*TParseCleanup)(unsafe.Pointer(pCleanup)).FpPtr)
|
|
_sqlite3DbNNFreeNN(tls, db, pCleanup)
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FaLabel != 0 {
|
|
_sqlite3DbNNFreeNN(tls, db, (*TParse)(unsafe.Pointer(pParse)).FaLabel)
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpConstExpr != 0 {
|
|
_sqlite3ExprListDelete(tls, db, (*TParse)(unsafe.Pointer(pParse)).FpConstExpr)
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbDisable -= uint32((*TParse)(unsafe.Pointer(pParse)).FdisableLookaside)
|
|
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)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpParse = (*TParse)(unsafe.Pointer(pParse)).FpOuterParse
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the fallback token corresponding to canonical token iToken, or
|
|
// ** 0 if iToken has no fallback.
|
|
// */
|
|
func _sqlite3ParserFallback(tls *libc.TLS, iToken int32) (r int32) {
|
|
return libc.Int32FromUint16(_yyFallback[iToken])
|
|
}
|
|
|
|
/************** End of parse.c ***********************************************/
|
|
/************** Begin file tokenize.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.
|
|
**
|
|
*************************************************************************
|
|
** An tokenizer for SQL
|
|
**
|
|
** This file contains C code that splits an SQL input string up into
|
|
** individual tokens and sends those tokens one-by-one over to the
|
|
** parser for analysis.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
/* #include <stdlib.h> */
|
|
|
|
/* Character classes for tokenizing
|
|
**
|
|
** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented
|
|
** using a lookup table, whereas a switch() directly on c uses a binary search.
|
|
** The lookup table is much faster. To maximize speed, and to ensure that
|
|
** a lookup table is used, all of the classes need to be small integers and
|
|
** all of them need to be used within the switch.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Drop a page from the cache. There must be exactly one reference to the
|
|
// ** page. This function deletes that reference, so after it returns the
|
|
// ** page pointed to by p is invalid.
|
|
// */
|
|
func _sqlite3PcacheDrop(tls *libc.TLS, p uintptr) {
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(p)).Fflags)&int32(PGHDR_DIRTY) != 0 {
|
|
_pcacheManageDirtyList(tls, p, uint8(PCACHE_DIRTYLIST_REMOVE))
|
|
}
|
|
(*TPCache)(unsafe.Pointer((*TPgHdr)(unsafe.Pointer(p)).FpCache)).FnRefSum = (*TPCache)(unsafe.Pointer((*TPgHdr)(unsafe.Pointer(p)).FpCache)).FnRefSum - 1
|
|
(*(*func(*libc.TLS, uintptr, uintptr, int32))(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fpcache2.FxUnpin})))(tls, (*TPCache)(unsafe.Pointer((*TPgHdr)(unsafe.Pointer(p)).FpCache)).FpCache, (*TPgHdr)(unsafe.Pointer(p)).FpPage, int32(1))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Try to obtain a page from the cache.
|
|
// **
|
|
// ** This routine returns a pointer to an sqlite3_pcache_page object if
|
|
// ** such an object is already in cache, or if a new one is created.
|
|
// ** This routine returns a NULL pointer if the object was not in cache
|
|
// ** and could not be created.
|
|
// **
|
|
// ** The createFlags should be 0 to check for existing pages and should
|
|
// ** be 3 (not 1, but 3) to try to create a new page.
|
|
// **
|
|
// ** If the createFlag is 0, then NULL is always returned if the page
|
|
// ** is not already in the cache. If createFlag is 1, then a new page
|
|
// ** is created only if that can be done without spilling dirty pages
|
|
// ** and without exceeding the cache size limit.
|
|
// **
|
|
// ** The caller needs to invoke sqlite3PcacheFetchFinish() to properly
|
|
// ** initialize the sqlite3_pcache_page object and convert it into a
|
|
// ** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish()
|
|
// ** routines are split this way for performance reasons. When separated
|
|
// ** they can both (usually) operate without having to push values to
|
|
// ** the stack on entry and pop them back off on exit, which saves a
|
|
// ** lot of pushing and popping.
|
|
// */
|
|
func _sqlite3PcacheFetch(tls *libc.TLS, pCache uintptr, pgno TPgno, createFlag int32) (r uintptr) {
|
|
var eCreate int32
|
|
var pRes uintptr
|
|
_, _ = eCreate, pRes
|
|
/* eCreate defines what to do if the page does not exist.
|
|
** 0 Do not allocate a new page. (createFlag==0)
|
|
** 1 Allocate a new page if doing so is inexpensive.
|
|
** (createFlag==1 AND bPurgeable AND pDirty)
|
|
** 2 Allocate a new page even it doing so is difficult.
|
|
** (createFlag==1 AND !(bPurgeable AND pDirty)
|
|
*/
|
|
eCreate = createFlag & libc.Int32FromUint8((*TPCache)(unsafe.Pointer(pCache)).FeCreate)
|
|
pRes = (*(*func(*libc.TLS, uintptr, uint32, int32) uintptr)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fpcache2.FxFetch})))(tls, (*TPCache)(unsafe.Pointer(pCache)).FpCache, pgno, eCreate)
|
|
return pRes
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the sqlite3PcacheFetch() routine is unable to allocate a new
|
|
// ** page because no clean pages are available for reuse and the cache
|
|
// ** size limit has been reached, then this routine can be invoked to
|
|
// ** try harder to allocate a page. This routine might invoke the stress
|
|
// ** callback to spill dirty pages to the journal. It will then try to
|
|
// ** allocate the new page and will only fail to allocate a new page on
|
|
// ** an OOM error.
|
|
// **
|
|
// ** This routine should be invoked only after sqlite3PcacheFetch() fails.
|
|
// */
|
|
func _sqlite3PcacheFetchStress(tls *libc.TLS, pCache uintptr, pgno TPgno, ppPage uintptr) (r int32) {
|
|
var pPg uintptr
|
|
var rc, v3 int32
|
|
_, _, _ = pPg, rc, v3
|
|
if libc.Int32FromUint8((*TPCache)(unsafe.Pointer(pCache)).FeCreate) == int32(2) {
|
|
return 0
|
|
}
|
|
if _sqlite3PcachePagecount(tls, pCache) > (*TPCache)(unsafe.Pointer(pCache)).FszSpill {
|
|
/* Find a dirty page to write-out and recycle. First try to find a
|
|
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
|
|
** cleared), but if that is not possible settle for any other
|
|
** unreferenced dirty page.
|
|
**
|
|
** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
|
|
** flag is currently referenced, then the following may leave pSynced
|
|
** set incorrectly (pointing to other than the LRU page with NEED_SYNC
|
|
** cleared). This is Ok, as pSynced is just an optimization. */
|
|
pPg = (*TPCache)(unsafe.Pointer(pCache)).FpSynced
|
|
for {
|
|
if !(pPg != 0 && ((*TPgHdr)(unsafe.Pointer(pPg)).FnRef != 0 || libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(pPg)).Fflags)&int32(PGHDR_NEED_SYNC) != 0)) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pPg = (*TPgHdr)(unsafe.Pointer(pPg)).FpDirtyPrev
|
|
}
|
|
(*TPCache)(unsafe.Pointer(pCache)).FpSynced = pPg
|
|
if !(pPg != 0) {
|
|
pPg = (*TPCache)(unsafe.Pointer(pCache)).FpDirtyTail
|
|
for {
|
|
if !(pPg != 0 && (*TPgHdr)(unsafe.Pointer(pPg)).FnRef != 0) {
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pPg = (*TPgHdr)(unsafe.Pointer(pPg)).FpDirtyPrev
|
|
}
|
|
}
|
|
if pPg != 0 {
|
|
rc = (*(*func(*libc.TLS, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{(*TPCache)(unsafe.Pointer(pCache)).FxStress})))(tls, (*TPCache)(unsafe.Pointer(pCache)).FpStress, pPg)
|
|
if rc != SQLITE_OK && rc != int32(SQLITE_BUSY) {
|
|
return rc
|
|
}
|
|
}
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppPage)) = (*(*func(*libc.TLS, uintptr, uint32, int32) uintptr)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fpcache2.FxFetch})))(tls, (*TPCache)(unsafe.Pointer(pCache)).FpCache, pgno, int32(2))
|
|
if **(**uintptr)(__ccgo_up(ppPage)) == uintptr(0) {
|
|
v3 = int32(SQLITE_NOMEM)
|
|
} else {
|
|
v3 = SQLITE_OK
|
|
}
|
|
return v3
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change the page number of page p to newPgno.
|
|
// */
|
|
func _sqlite3PcacheMove(tls *libc.TLS, p uintptr, newPgno TPgno) {
|
|
var pCache, pOther, pXPage uintptr
|
|
_, _, _ = pCache, pOther, pXPage
|
|
pCache = (*TPgHdr)(unsafe.Pointer(p)).FpCache
|
|
pOther = (*(*func(*libc.TLS, uintptr, uint32, int32) uintptr)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fpcache2.FxFetch})))(tls, (*TPCache)(unsafe.Pointer(pCache)).FpCache, newPgno, 0)
|
|
if pOther != 0 {
|
|
pXPage = (*Tsqlite3_pcache_page)(unsafe.Pointer(pOther)).FpExtra
|
|
(*TPgHdr)(unsafe.Pointer(pXPage)).FnRef = (*TPgHdr)(unsafe.Pointer(pXPage)).FnRef + 1
|
|
(*TPCache)(unsafe.Pointer(pCache)).FnRefSum = (*TPCache)(unsafe.Pointer(pCache)).FnRefSum + 1
|
|
_sqlite3PcacheDrop(tls, pXPage)
|
|
}
|
|
(*(*func(*libc.TLS, uintptr, uintptr, uint32, uint32))(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fpcache2.FxRekey})))(tls, (*TPCache)(unsafe.Pointer(pCache)).FpCache, (*TPgHdr)(unsafe.Pointer(p)).FpPage, (*TPgHdr)(unsafe.Pointer(p)).Fpgno, newPgno)
|
|
(*TPgHdr)(unsafe.Pointer(p)).Fpgno = newPgno
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(p)).Fflags)&int32(PGHDR_DIRTY) != 0 && libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(p)).Fflags)&int32(PGHDR_NEED_SYNC) != 0 {
|
|
_pcacheManageDirtyList(tls, p, uint8(PCACHE_DIRTYLIST_FRONT))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called to free superfluous dynamically allocated memory
|
|
// ** held by the pager system. Memory in use by any SQLite pager allocated
|
|
// ** by the current thread may be sqlite3_free()ed.
|
|
// **
|
|
// ** nReq is the number of bytes of memory required. Once this much has
|
|
// ** been released, the function returns. The return value is the total number
|
|
// ** of bytes of memory released.
|
|
// */
|
|
func _sqlite3PcacheReleaseMemory(tls *libc.TLS, nReq int32) (r int32) {
|
|
var nFree int32
|
|
var p, v1 uintptr
|
|
var v2 bool
|
|
_, _, _, _ = nFree, p, v1, v2
|
|
nFree = 0
|
|
if _sqlite3Config.FpPage == uintptr(0) {
|
|
Xsqlite3_mutex_enter(tls, (*TPGroup)(unsafe.Pointer(uintptr(unsafe.Pointer(&_pcache1_g)))).Fmutex)
|
|
for {
|
|
if v2 = nReq < 0 || nFree < nReq; v2 {
|
|
v1 = _pcache1_g.Fgrp.Flru.FpLruPrev
|
|
p = v1
|
|
}
|
|
if !(v2 && v1 != uintptr(0) && libc.Int32FromUint16((*TPgHdr1)(unsafe.Pointer(p)).FisAnchor) == 0) {
|
|
break
|
|
}
|
|
nFree = nFree + _pcache1MemSize(tls, (*TPgHdr1)(unsafe.Pointer(p)).Fpage.FpBuf)
|
|
_pcache1PinPage(tls, p)
|
|
_pcache1RemoveFromHash(tls, p, int32(1))
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*TPGroup)(unsafe.Pointer(uintptr(unsafe.Pointer(&_pcache1_g)))).Fmutex)
|
|
}
|
|
return nFree
|
|
}
|
|
|
|
/************** End of pcache1.c *********************************************/
|
|
/************** Begin file rowset.c ******************************************/
|
|
/*
|
|
** 2008 December 3
|
|
**
|
|
** 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 module implements an object we call a "RowSet".
|
|
**
|
|
** The RowSet object is a collection of rowids. Rowids
|
|
** are inserted into the RowSet in an arbitrary order. Inserts
|
|
** can be intermixed with tests to see if a given rowid has been
|
|
** previously inserted into the RowSet.
|
|
**
|
|
** After all inserts are finished, it is possible to extract the
|
|
** elements of the RowSet in sorted order. Once this extraction
|
|
** process has started, no new elements may be inserted.
|
|
**
|
|
** Hence, the primitive operations for a RowSet are:
|
|
**
|
|
** CREATE
|
|
** INSERT
|
|
** TEST
|
|
** SMALLEST
|
|
** DESTROY
|
|
**
|
|
** The CREATE and DESTROY primitives are the constructor and destructor,
|
|
** obviously. The INSERT primitive adds a new element to the RowSet.
|
|
** TEST checks to see if an element is already in the RowSet. SMALLEST
|
|
** extracts the least value from the RowSet.
|
|
**
|
|
** The INSERT primitive might allocate additional memory. Memory is
|
|
** allocated in chunks so most INSERTs do no allocation. There is an
|
|
** upper bound on the size of allocated memory. No memory is freed
|
|
** until DESTROY.
|
|
**
|
|
** The TEST primitive includes a "batch" number. The TEST primitive
|
|
** will only see elements that were inserted before the last change
|
|
** in the batch number. In other words, if an INSERT occurs between
|
|
** two TESTs where the TESTs have the same batch number, then the
|
|
** value added by the INSERT will not be visible to the second TEST.
|
|
** The initial batch number is zero, so if the very first TEST contains
|
|
** a non-zero batch number, it will see all prior INSERTs.
|
|
**
|
|
** No INSERTs may occurs after a SMALLEST. An assertion will fail if
|
|
** that is attempted.
|
|
**
|
|
** The cost of an INSERT is roughly constant. (Sometimes new memory
|
|
** has to be allocated on an INSERT.) The cost of a TEST with a new
|
|
** batch number is O(NlogN) where N is the number of elements in the RowSet.
|
|
** The cost of a TEST using the same batch number is O(logN). The cost
|
|
** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST
|
|
** primitives are constant time. The cost of DESTROY is O(N).
|
|
**
|
|
** TEST and SMALLEST may not be used by the same RowSet. This used to
|
|
** be possible, but the feature was not used, so it was removed in order
|
|
** to simplify the code.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
/*
|
|
** Target size for allocation chunks.
|
|
*/
|
|
|
|
/*
|
|
** The number of rowset entries per allocation chunk.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if zTabName is really the name of a pragma. If it is,
|
|
// ** then register an eponymous virtual table for that pragma and return
|
|
// ** a pointer to the Module object for the new virtual table.
|
|
// */
|
|
func _sqlite3PragmaVtabRegister(tls *libc.TLS, db uintptr, zName uintptr) (r uintptr) {
|
|
var pName uintptr
|
|
_ = pName
|
|
pName = _pragmaLocate(tls, zName+uintptr(7))
|
|
if pName == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
if libc.Int32FromUint8((*TPragmaName)(unsafe.Pointer(pName)).FmPragFlg)&(libc.Int32FromInt32(PragFlg_Result0)|libc.Int32FromInt32(PragFlg_Result1)) == 0 {
|
|
return uintptr(0)
|
|
}
|
|
return _sqlite3VtabCreateModule(tls, db, zName, uintptr(unsafe.Pointer(&_pragmaVtabModule)), pName, uintptr(0))
|
|
}
|
|
|
|
/************** End of pragma.c **********************************************/
|
|
/************** Begin file prepare.c *****************************************/
|
|
/*
|
|
** 2005 May 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 the implementation of the sqlite3_prepare()
|
|
** interface, and routines that contribute to loading the database schema
|
|
** from disk.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change the size of an existing memory allocation
|
|
// */
|
|
func _sqlite3Realloc(tls *libc.TLS, pOld uintptr, nBytes Tu64) (r uintptr) {
|
|
var nDiff, nNew, nOld int32
|
|
var nUsed, v1 Tsqlite3_int64
|
|
var pNew uintptr
|
|
var v2 bool
|
|
_, _, _, _, _, _, _ = nDiff, nNew, nOld, nUsed, pNew, v1, v2
|
|
if pOld == uintptr(0) {
|
|
return _sqlite3Malloc(tls, nBytes) /* IMP: R-04300-56712 */
|
|
}
|
|
if nBytes == uint64(0) {
|
|
Xsqlite3_free(tls, pOld) /* IMP: R-26507-47431 */
|
|
return uintptr(0)
|
|
}
|
|
if nBytes > uint64(SQLITE_MAX_ALLOCATION_SIZE) {
|
|
return uintptr(0)
|
|
}
|
|
nOld = _sqlite3MallocSize(tls, pOld)
|
|
/* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second
|
|
** argument to xRealloc is always a value returned by a prior call to
|
|
** xRoundup. */
|
|
nNew = (*(*func(*libc.TLS, int32) int32)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fm.FxRoundup})))(tls, libc.Int32FromUint64(nBytes))
|
|
if nOld == nNew {
|
|
pNew = pOld
|
|
} else {
|
|
if _sqlite3Config.FbMemstat != 0 {
|
|
Xsqlite3_mutex_enter(tls, _mem0.Fmutex)
|
|
_sqlite3StatusHighwater(tls, int32(SQLITE_STATUS_MALLOC_SIZE), libc.Int32FromUint64(nBytes))
|
|
nDiff = nNew - nOld
|
|
if v2 = nDiff > 0; v2 {
|
|
v1 = _sqlite3StatusValue(tls, SQLITE_STATUS_MEMORY_USED)
|
|
nUsed = v1
|
|
}
|
|
if v2 && v1 >= _mem0.FalarmThreshold-int64(nDiff) {
|
|
_sqlite3MallocAlarm(tls, nDiff)
|
|
if _mem0.FhardLimit > 0 && nUsed >= _mem0.FhardLimit-int64(nDiff) {
|
|
Xsqlite3_mutex_leave(tls, _mem0.Fmutex)
|
|
return uintptr(0)
|
|
}
|
|
}
|
|
pNew = (*(*func(*libc.TLS, uintptr, int32) uintptr)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fm.FxRealloc})))(tls, pOld, nNew)
|
|
if pNew == uintptr(0) && _mem0.FalarmThreshold > 0 {
|
|
_sqlite3MallocAlarm(tls, libc.Int32FromUint64(nBytes))
|
|
pNew = (*(*func(*libc.TLS, uintptr, int32) uintptr)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fm.FxRealloc})))(tls, pOld, nNew)
|
|
}
|
|
if pNew != 0 {
|
|
nNew = _sqlite3MallocSize(tls, pNew)
|
|
_sqlite3StatusUp(tls, SQLITE_STATUS_MEMORY_USED, nNew-nOld)
|
|
}
|
|
Xsqlite3_mutex_leave(tls, _mem0.Fmutex)
|
|
} else {
|
|
pNew = (*(*func(*libc.TLS, uintptr, int32) uintptr)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fm.FxRealloc})))(tls, pOld, nNew)
|
|
}
|
|
}
|
|
/* IMP: R-11148-40995 */
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize a SelectDest structure.
|
|
// */
|
|
func _sqlite3SelectDestInit(tls *libc.TLS, pDest uintptr, eDest int32, iParm int32) {
|
|
(*TSelectDest)(unsafe.Pointer(pDest)).FeDest = libc.Uint8FromInt32(eDest)
|
|
(*TSelectDest)(unsafe.Pointer(pDest)).FiSDParm = iParm
|
|
(*TSelectDest)(unsafe.Pointer(pDest)).FiSDParm2 = 0
|
|
(*TSelectDest)(unsafe.Pointer(pDest)).FzAffSdst = uintptr(0)
|
|
(*TSelectDest)(unsafe.Pointer(pDest)).FiSdst = 0
|
|
(*TSelectDest)(unsafe.Pointer(pDest)).FnSdst = 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Extract the iCol-th column from the nRec-byte record in pRec. Write
|
|
// ** the column value into *ppVal. If *ppVal is initially NULL then a new
|
|
// ** sqlite3_value object is allocated.
|
|
// **
|
|
// ** If *ppVal is initially NULL then the caller is responsible for
|
|
// ** ensuring that the value written into *ppVal is eventually freed.
|
|
// **
|
|
// ** If the buffer does not contain a well-formed record, this routine may
|
|
// ** read several bytes past the end of the buffer. Callers must therefore
|
|
// ** ensure that any buffer which may contain a corrupt record is padded
|
|
// ** with at least 8 bytes of addressable memory.
|
|
// */
|
|
func _sqlite3Stat4Column(tls *libc.TLS, db uintptr, pRec uintptr, nRec int32, iCol int32, ppVal uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var a, pMem, v4 uintptr
|
|
var i, v1 int32
|
|
var iField Ti64
|
|
var iHdr, szField Tu32
|
|
var _ /* nHdr at bp+4 */ Tu32
|
|
var _ /* t at bp+0 */ Tu32
|
|
_, _, _, _, _, _, _, _ = a, i, iField, iHdr, pMem, szField, v1, v4
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0) /* Next unread data byte */
|
|
szField = uint32(0) /* Column index */
|
|
a = pRec /* Typecast byte array */
|
|
pMem = **(**uintptr)(__ccgo_up(ppVal)) /* Write result into this Mem object */
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(a))) < libc.Int32FromUint8(libc.Uint8FromInt32(0x80)) {
|
|
**(**Tu32)(__ccgo_up(bp + 4)) = uint32(**(**Tu8)(__ccgo_up(a)))
|
|
v1 = libc.Int32FromInt32(1)
|
|
} else {
|
|
v1 = libc.Int32FromUint8(_sqlite3GetVarint32(tls, a, bp+4))
|
|
}
|
|
iHdr = uint32(libc.Uint8FromInt32(v1))
|
|
if **(**Tu32)(__ccgo_up(bp + 4)) > libc.Uint32FromInt32(nRec) || iHdr >= **(**Tu32)(__ccgo_up(bp + 4)) {
|
|
return _sqlite3CorruptError(tls, int32(87782))
|
|
}
|
|
iField = libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp + 4)))
|
|
i = 0
|
|
for {
|
|
if !(i <= iCol) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(a + uintptr(iHdr)))) < libc.Int32FromUint8(libc.Uint8FromInt32(0x80)) {
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(**(**Tu8)(__ccgo_up(a + uintptr(iHdr))))
|
|
v1 = libc.Int32FromInt32(1)
|
|
} else {
|
|
v1 = libc.Int32FromUint8(_sqlite3GetVarint32(tls, a+uintptr(iHdr), bp))
|
|
}
|
|
iHdr = iHdr + uint32(libc.Uint8FromInt32(v1))
|
|
if iHdr > **(**Tu32)(__ccgo_up(bp + 4)) {
|
|
return _sqlite3CorruptError(tls, int32(87788))
|
|
}
|
|
szField = _sqlite3VdbeSerialTypeLen(tls, **(**Tu32)(__ccgo_up(bp)))
|
|
iField = iField + libc.Int64FromUint32(szField)
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if iField > int64(nRec) {
|
|
return _sqlite3CorruptError(tls, int32(87794))
|
|
}
|
|
if pMem == uintptr(0) {
|
|
v4 = _sqlite3ValueNew(tls, db)
|
|
**(**uintptr)(__ccgo_up(ppVal)) = v4
|
|
pMem = v4
|
|
if pMem == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
_sqlite3VdbeSerialGet(tls, a+uintptr(iField-libc.Int64FromUint32(szField)), **(**Tu32)(__ccgo_up(bp)), pMem)
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = (*Tsqlite3)(unsafe.Pointer(db)).Fenc
|
|
return SQLITE_OK
|
|
}
|
|
|
|
func _sqlite3StrAccumEnlargeIfNeeded(tls *libc.TLS, p uintptr, N Ti64) (r int32) {
|
|
if N+libc.Int64FromUint32((*TStrAccum)(unsafe.Pointer(p)).FnChar) >= libc.Int64FromUint32((*TStrAccum)(unsafe.Pointer(p)).FnAlloc) {
|
|
_sqlite3StrAccumEnlarge(tls, p, N)
|
|
}
|
|
return libc.Int32FromUint8((*TStrAccum)(unsafe.Pointer(p)).FaccError)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize a string accumulator.
|
|
// **
|
|
// ** p: The accumulator to be initialized.
|
|
// ** db: Pointer to a database connection. May be NULL. Lookaside
|
|
// ** memory is used if not NULL. db->mallocFailed is set appropriately
|
|
// ** when not NULL.
|
|
// ** zBase: An initial buffer. May be NULL in which case the initial buffer
|
|
// ** is malloced.
|
|
// ** n: Size of zBase in bytes. If total space requirements never exceed
|
|
// ** n then no memory allocations ever occur.
|
|
// ** mx: Maximum number of bytes to accumulate. If mx==0 then no memory
|
|
// ** allocations will ever occur.
|
|
// */
|
|
func _sqlite3StrAccumInit(tls *libc.TLS, p uintptr, db uintptr, zBase uintptr, n int32, mx int32) {
|
|
(*TStrAccum)(unsafe.Pointer(p)).FzText = zBase
|
|
(*TStrAccum)(unsafe.Pointer(p)).Fdb = db
|
|
(*TStrAccum)(unsafe.Pointer(p)).FnAlloc = libc.Uint32FromInt32(n)
|
|
(*TStrAccum)(unsafe.Pointer(p)).FmxAlloc = libc.Uint32FromInt32(mx)
|
|
(*TStrAccum)(unsafe.Pointer(p)).FnChar = uint32(0)
|
|
(*TStrAccum)(unsafe.Pointer(p)).FaccError = uint8(0)
|
|
(*TStrAccum)(unsafe.Pointer(p)).FprintfFlags = uint8(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the StrAccum object to an error mode.
|
|
// */
|
|
func _sqlite3StrAccumSetError(tls *libc.TLS, p uintptr, eError Tu8) {
|
|
(*TStrAccum)(unsafe.Pointer(p)).FaccError = eError
|
|
if (*TStrAccum)(unsafe.Pointer(p)).FmxAlloc != 0 {
|
|
Xsqlite3_str_reset(tls, p)
|
|
}
|
|
if libc.Int32FromUint8(eError) == int32(SQLITE_TOOBIG) {
|
|
_sqlite3ErrorToParser(tls, (*TStrAccum)(unsafe.Pointer(p)).Fdb, libc.Int32FromUint8(eError))
|
|
}
|
|
}
|
|
|
|
func _sqlite3StrICmp(tls *libc.TLS, zLeft uintptr, zRight uintptr) (r int32) {
|
|
var a, b uintptr
|
|
var c, x int32
|
|
_, _, _, _ = a, b, c, x
|
|
a = zLeft
|
|
b = zRight
|
|
for {
|
|
c = libc.Int32FromUint8(**(**uint8)(__ccgo_up(a)))
|
|
x = libc.Int32FromUint8(**(**uint8)(__ccgo_up(b)))
|
|
if c == x {
|
|
if c == 0 {
|
|
break
|
|
}
|
|
} else {
|
|
c = libc.Int32FromUint8(_sqlite3UpperToLower[c]) - libc.Int32FromUint8(_sqlite3UpperToLower[x])
|
|
if c != 0 {
|
|
break
|
|
}
|
|
}
|
|
a = a + 1
|
|
b = b + 1
|
|
goto _1
|
|
_1:
|
|
}
|
|
return c
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Backwards Compatibility Hack:
|
|
// **
|
|
// ** Historical versions of SQLite accepted strings as column names in
|
|
// ** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example:
|
|
// **
|
|
// ** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim)
|
|
// ** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC);
|
|
// **
|
|
// ** This is goofy. But to preserve backwards compatibility we continue to
|
|
// ** accept it. This routine does the necessary conversion. It converts
|
|
// ** the expression given in its argument from a TK_STRING into a TK_ID
|
|
// ** if the expression is just a TK_STRING with an optional COLLATE clause.
|
|
// ** If the expression is anything other than TK_STRING, the expression is
|
|
// ** unchanged.
|
|
// */
|
|
func _sqlite3StringToId(tls *libc.TLS, p uintptr) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_STRING) {
|
|
(*TExpr)(unsafe.Pointer(p)).Fop = uint8(TK_ID)
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_COLLATE) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(p)).FpLeft)).Fop) == int32(TK_STRING) {
|
|
(*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(p)).FpLeft)).Fop = uint8(TK_ID)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert an table column number into a index column number. That is,
|
|
// ** for the column iCol in the table (as defined by the CREATE TABLE statement)
|
|
// ** find the (first) offset of that column in index pIdx. Or return -1
|
|
// ** if column iCol is not used in index pIdx.
|
|
// */
|
|
func _sqlite3TableColumnToIndex(tls *libc.TLS, pIdx uintptr, iCol int32) (r int32) {
|
|
var i int32
|
|
var iCol16 Ti16
|
|
_, _ = i, iCol16
|
|
iCol16 = int16(iCol)
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)) {
|
|
break
|
|
}
|
|
if int32(iCol16) == int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i)*2))) {
|
|
return i
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return -int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function returns true if main-memory should be used instead of
|
|
// ** a temporary file for transient pager files and statement journals.
|
|
// ** The value returned depends on the value of db->temp_store (runtime
|
|
// ** parameter) and the compile time value of SQLITE_TEMP_STORE. The
|
|
// ** following table describes the relationship between these two values
|
|
// ** and this functions return value.
|
|
// **
|
|
// ** SQLITE_TEMP_STORE db->temp_store Location of temporary database
|
|
// ** ----------------- -------------- ------------------------------
|
|
// ** 0 any file (return 0)
|
|
// ** 1 1 file (return 0)
|
|
// ** 1 2 memory (return 1)
|
|
// ** 1 0 file (return 0)
|
|
// ** 2 1 file (return 0)
|
|
// ** 2 2 memory (return 1)
|
|
// ** 2 0 memory (return 1)
|
|
// ** 3 any memory (return 1)
|
|
// */
|
|
func _sqlite3TempInMemory(tls *libc.TLS, db uintptr) (r int32) {
|
|
return libc.BoolInt32(libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).Ftemp_store) == int32(2))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate a Token object from a string
|
|
// */
|
|
func _sqlite3TokenInit(tls *libc.TLS, p uintptr, z uintptr) {
|
|
(*TToken)(unsafe.Pointer(p)).Fz = z
|
|
(*TToken)(unsafe.Pointer(p)).Fn = libc.Uint32FromInt32(_sqlite3Strlen30(tls, z))
|
|
}
|
|
|
|
/* Convenient short-hand */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Construct a trigger step that implements a DELETE statement and return
|
|
// ** a pointer to that trigger step. The parser calls this routine when it
|
|
// ** sees a DELETE statement inside the body of a CREATE TRIGGER.
|
|
// */
|
|
func _sqlite3TriggerDeleteStep(tls *libc.TLS, pParse uintptr, pTabList uintptr, pWhere uintptr, zStart uintptr, zEnd uintptr) (r uintptr) {
|
|
var db, pTriggerStep uintptr
|
|
_, _ = db, pTriggerStep
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pTriggerStep = _triggerStepAllocate(tls, pParse, uint8(TK_DELETE), pTabList, zStart, zEnd)
|
|
if pTriggerStep != 0 {
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpWhere = pWhere
|
|
pWhere = uintptr(0)
|
|
} else {
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpWhere = _sqlite3ExprDup(tls, db, pWhere, int32(EXPRDUP_REDUCE))
|
|
}
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).Forconf = uint8(OE_Default)
|
|
}
|
|
_sqlite3ExprDelete(tls, db, pWhere)
|
|
return pTriggerStep
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Build a trigger step out of an INSERT statement. Return a pointer
|
|
// ** to the new trigger step.
|
|
// **
|
|
// ** The parser calls this routine when it sees an INSERT inside the
|
|
// ** body of a trigger.
|
|
// */
|
|
func _sqlite3TriggerInsertStep(tls *libc.TLS, pParse uintptr, pTabList uintptr, pColumn uintptr, pSelect uintptr, orconf Tu8, pUpsert uintptr, zStart uintptr, zEnd uintptr) (r uintptr) {
|
|
var db, pTriggerStep uintptr
|
|
_, _ = db, pTriggerStep
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pTriggerStep = _triggerStepAllocate(tls, pParse, uint8(TK_INSERT), pTabList, zStart, zEnd)
|
|
if pTriggerStep != 0 {
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpSelect = pSelect
|
|
pSelect = uintptr(0)
|
|
} else {
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpSelect = _sqlite3SelectDup(tls, db, pSelect, int32(EXPRDUP_REDUCE))
|
|
}
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpIdList = pColumn
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpUpsert = pUpsert
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).Forconf = orconf
|
|
if pUpsert != 0 {
|
|
_sqlite3HasExplicitNulls(tls, pParse, (*TUpsert)(unsafe.Pointer(pUpsert)).FpUpsertTarget)
|
|
}
|
|
} else {
|
|
_sqlite3IdListDelete(tls, db, pColumn)
|
|
_sqlite3UpsertDelete(tls, db, pUpsert)
|
|
}
|
|
_sqlite3SelectDelete(tls, db, pSelect)
|
|
return pTriggerStep
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Construct a trigger step that implements an UPDATE statement and return
|
|
// ** a pointer to that trigger step. The parser calls this routine when it
|
|
// ** sees an UPDATE statement inside the body of a CREATE TRIGGER.
|
|
// */
|
|
func _sqlite3TriggerUpdateStep(tls *libc.TLS, pParse uintptr, pTabList uintptr, pFrom uintptr, pEList uintptr, pWhere uintptr, orconf Tu8, zStart uintptr, zEnd uintptr) (r uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pFromDup, pSub, pTriggerStep uintptr
|
|
var _ /* as at bp+0 */ TToken
|
|
_, _, _, _ = db, pFromDup, pSub, pTriggerStep
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pTriggerStep = _triggerStepAllocate(tls, pParse, uint8(TK_UPDATE), pTabList, zStart, zEnd)
|
|
if pTriggerStep != 0 {
|
|
pFromDup = uintptr(0)
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpExprList = pEList
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpWhere = pWhere
|
|
pFromDup = pFrom
|
|
pEList = uintptr(0)
|
|
pWhere = uintptr(0)
|
|
pFrom = uintptr(0)
|
|
} else {
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpExprList = _sqlite3ExprListDup(tls, db, pEList, int32(EXPRDUP_REDUCE))
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpWhere = _sqlite3ExprDup(tls, db, pWhere, int32(EXPRDUP_REDUCE))
|
|
pFromDup = _sqlite3SrcListDup(tls, db, pFrom, int32(EXPRDUP_REDUCE))
|
|
}
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).Forconf = orconf
|
|
if pFromDup != 0 && !(libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= libc.Int32FromInt32(PARSE_MODE_RENAME)) {
|
|
**(**TToken)(__ccgo_up(bp)) = TToken{}
|
|
pSub = _sqlite3SelectNew(tls, pParse, uintptr(0), pFromDup, uintptr(0), uintptr(0), uintptr(0), uintptr(0), uint32(SF_NestedFrom), uintptr(0))
|
|
pFromDup = _sqlite3SrcListAppendFromTerm(tls, pParse, uintptr(0), uintptr(0), uintptr(0), bp, pSub, uintptr(0))
|
|
}
|
|
if pFromDup != 0 && (*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpSrc != 0 {
|
|
(*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpSrc = _sqlite3SrcListAppendList(tls, pParse, (*TTriggerStep)(unsafe.Pointer(pTriggerStep)).FpSrc, pFromDup)
|
|
} else {
|
|
_sqlite3SrcListDelete(tls, db, pFromDup)
|
|
}
|
|
}
|
|
_sqlite3ExprListDelete(tls, db, pEList)
|
|
_sqlite3ExprDelete(tls, db, pWhere)
|
|
_sqlite3SrcListDelete(tls, db, pFrom)
|
|
return pTriggerStep
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
|
|
// ** return the number of unicode characters in pZ up to (but not including)
|
|
// ** the first 0x00 byte. If nByte is not less than zero, return the
|
|
// ** number of unicode characters in the first nByte of pZ (or up to
|
|
// ** the first 0x00, whichever comes first).
|
|
// */
|
|
func _sqlite3Utf8CharLen(tls *libc.TLS, zIn uintptr, nByte int32) (r1 int32) {
|
|
var r int32
|
|
var z, zTerm, v1 uintptr
|
|
_, _, _, _ = r, z, zTerm, v1
|
|
r = 0
|
|
z = zIn
|
|
if nByte >= 0 {
|
|
zTerm = z + uintptr(nByte)
|
|
} else {
|
|
zTerm = uintptr(-libc.Int32FromInt32(1))
|
|
}
|
|
for libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z))) != 0 && z < zTerm {
|
|
v1 = z
|
|
z = z + 1
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1))) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z)))&int32(0xc0) == int32(0x80) {
|
|
z = z + 1
|
|
}
|
|
}
|
|
r = r + 1
|
|
}
|
|
return r
|
|
}
|
|
|
|
/* This test function is not currently used by the automated test-suite.
|
|
** Hence it is only available in debug builds.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Translate a single UTF-8 character. Return the unicode value.
|
|
// **
|
|
// ** During translation, assume that the byte that zTerm points
|
|
// ** is a 0x00.
|
|
// **
|
|
// ** Write a pointer to the next unread byte back into *pzNext.
|
|
// **
|
|
// ** Notes On Invalid UTF-8:
|
|
// **
|
|
// ** * This routine never allows a 7-bit character (0x00 through 0x7f) to
|
|
// ** be encoded as a multi-byte character. Any multi-byte character that
|
|
// ** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd.
|
|
// **
|
|
// ** * This routine never allows a UTF16 surrogate value to be encoded.
|
|
// ** If a multi-byte character attempts to encode a value between
|
|
// ** 0xd800 and 0xe000 then it is rendered as 0xfffd.
|
|
// **
|
|
// ** * Bytes in the range of 0x80 through 0xbf which occur as the first
|
|
// ** byte of a character are interpreted as single-byte characters
|
|
// ** and rendered as themselves even though they are technically
|
|
// ** invalid characters.
|
|
// **
|
|
// ** * This routine accepts over-length UTF8 encodings
|
|
// ** for unicode values 0x80 and greater. It does not change over-length
|
|
// ** encodings to 0xfffd as some systems recommend.
|
|
// */
|
|
func _sqlite3Utf8Read(tls *libc.TLS, pz uintptr) (r Tu32) {
|
|
var c uint32
|
|
var v1, v2 uintptr
|
|
_, _, _ = c, v1, v2
|
|
/* Same as READ_UTF8() above but without the zTerm parameter.
|
|
** For this routine, we assume the UTF8 string is always zero-terminated.
|
|
*/
|
|
v2 = pz
|
|
v1 = *(*uintptr)(unsafe.Pointer(v2))
|
|
*(*uintptr)(unsafe.Pointer(v2)) = *(*uintptr)(unsafe.Pointer(v2)) + 1
|
|
c = uint32(**(**uint8)(__ccgo_up(v1)))
|
|
if c >= uint32(0xc0) {
|
|
c = uint32(_sqlite3Utf8Trans1[c-uint32(0xc0)])
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(**(**uintptr)(__ccgo_up(pz)))))&int32(0xc0) == int32(0x80) {
|
|
v2 = pz
|
|
v1 = *(*uintptr)(unsafe.Pointer(v2))
|
|
*(*uintptr)(unsafe.Pointer(v2)) = *(*uintptr)(unsafe.Pointer(v2)) + 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)
|
|
}
|
|
}
|
|
return c
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read a single UTF8 character out of buffer z[], but reading no
|
|
// ** more than n characters from the buffer. z[] is not zero-terminated.
|
|
// **
|
|
// ** Return the number of bytes used to construct the character.
|
|
// **
|
|
// ** Invalid UTF8 might generate a strange result. No effort is made
|
|
// ** to detect invalid UTF8.
|
|
// **
|
|
// ** At most 4 bytes will be read out of z[]. The return value will always
|
|
// ** be between 1 and 4.
|
|
// */
|
|
func _sqlite3Utf8ReadLimited(tls *libc.TLS, z uintptr, n int32, piOut uintptr) (r int32) {
|
|
var c Tu32
|
|
var i int32
|
|
_, _ = c, i
|
|
i = int32(1)
|
|
c = uint32(**(**Tu8)(__ccgo_up(z)))
|
|
if c >= uint32(0xc0) {
|
|
c = uint32(_sqlite3Utf8Trans1[c-uint32(0xc0)])
|
|
if n > int32(4) {
|
|
n = int32(4)
|
|
}
|
|
for i < n && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z + uintptr(i))))&int32(0xc0) == int32(0x80) {
|
|
c = c<<libc.Int32FromInt32(6) + libc.Uint32FromInt32(libc.Int32FromInt32(0x3f)&libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z + uintptr(i)))))
|
|
i = i + 1
|
|
}
|
|
}
|
|
**(**Tu32)(__ccgo_up(piOut)) = c
|
|
return i
|
|
}
|
|
|
|
/*
|
|
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
|
|
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
|
|
*/
|
|
/* #define TRANSLATE_TRACE 1 */
|
|
|
|
func _sqlite3ValueBytes(tls *libc.TLS, pVal uintptr, enc Tu8) (r int32) {
|
|
var p uintptr
|
|
_ = p
|
|
p = pVal
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Str) != 0 && libc.Int32FromUint8((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fenc) == libc.Int32FromUint8(enc) {
|
|
return (*TMem)(unsafe.Pointer(p)).Fn
|
|
}
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Str) != 0 && libc.Int32FromUint8(enc) != int32(SQLITE_UTF8) && libc.Int32FromUint8((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fenc) != int32(SQLITE_UTF8) {
|
|
return (*TMem)(unsafe.Pointer(p)).Fn
|
|
}
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Blob) != 0 {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Zero) != 0 {
|
|
return (*TMem)(unsafe.Pointer(p)).Fn + *(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(p)).Fu))
|
|
} else {
|
|
return (*TMem)(unsafe.Pointer(p)).Fn
|
|
}
|
|
}
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Null) != 0 {
|
|
return 0
|
|
}
|
|
return _valueBytes(tls, pVal, enc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Return true if sqlit3_value object pVal is a string or blob value
|
|
// ** that uses the destructor specified in the second argument.
|
|
// **
|
|
// ** TODO: Maybe someday promote this interface into a published API so
|
|
// ** that third-party extensions can get access to it?
|
|
// */
|
|
func _sqlite3ValueIsOfClass(tls *libc.TLS, pVal uintptr, __ccgo_fp_xFree uintptr) (r int32) {
|
|
if pVal != uintptr(0) && libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Blob)) != 0 && libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&int32(MEM_Dyn) != 0 && (*Tsqlite3_value)(unsafe.Pointer(pVal)).FxDel == __ccgo_fp_xFree {
|
|
return int32(1)
|
|
} else {
|
|
return 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* This function is only available internally, it is not part of the
|
|
// ** external API. It works in a similar way to sqlite3_value_text(),
|
|
// ** except the data returned is in the encoding specified by the second
|
|
// ** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
|
|
// ** SQLITE_UTF8.
|
|
// **
|
|
// ** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED.
|
|
// ** If that is the case, then the result must be aligned on an even byte
|
|
// ** boundary.
|
|
// */
|
|
func _sqlite3ValueText(tls *libc.TLS, pVal uintptr, enc Tu8) (r uintptr) {
|
|
if !(pVal != 0) {
|
|
return uintptr(0)
|
|
}
|
|
if libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Term)) == libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Term) && libc.Int32FromUint8((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fenc) == libc.Int32FromUint8(enc) {
|
|
return (*Tsqlite3_value)(unsafe.Pointer(pVal)).Fz
|
|
}
|
|
if libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&int32(MEM_Null) != 0 {
|
|
return uintptr(0)
|
|
}
|
|
return _valueToText(tls, pVal, enc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return 1 if pMem represents true, and return 0 if pMem represents false.
|
|
// ** Return the value ifNull if pMem is NULL.
|
|
// */
|
|
func _sqlite3VdbeBooleanValue(tls *libc.TLS, pMem uintptr, ifNull int32) (r int32) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
return libc.BoolInt32(*(*Ti64)(unsafe.Pointer(pMem)) != 0)
|
|
}
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Null) != 0 {
|
|
return ifNull
|
|
}
|
|
return libc.BoolInt32(_sqlite3VdbeRealValue(tls, pMem) != float64(0))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If pMem is an object with a valid string representation, this routine
|
|
// ** ensures the internal encoding for the string representation is
|
|
// ** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE.
|
|
// **
|
|
// ** If pMem is not a string object, or the encoding of the string
|
|
// ** representation is already stored using the requested encoding, then this
|
|
// ** routine is a no-op.
|
|
// **
|
|
// ** SQLITE_OK is returned if the conversion is successful (or not required).
|
|
// ** SQLITE_NOMEM may be returned if a malloc() fails during conversion
|
|
// ** between formats.
|
|
// */
|
|
func _sqlite3VdbeChangeEncoding(tls *libc.TLS, pMem uintptr, desiredEnc int32) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
if !(libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&libc.Int32FromInt32(MEM_Str) != 0) {
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = libc.Uint8FromInt32(desiredEnc)
|
|
return SQLITE_OK
|
|
}
|
|
if libc.Int32FromUint8((*TMem)(unsafe.Pointer(pMem)).Fenc) == desiredEnc {
|
|
return SQLITE_OK
|
|
}
|
|
/* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
|
|
** then the encoding of the value may not have changed.
|
|
*/
|
|
rc = _sqlite3VdbeMemTranslate(tls, pMem, libc.Uint8FromInt32(desiredEnc))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Free all memory associated with the Vdbe passed as the second argument,
|
|
// ** except for object itself, which is preserved.
|
|
// **
|
|
// ** The difference between this function and sqlite3VdbeDelete() is that
|
|
// ** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
|
|
// ** the database connection and frees the object itself.
|
|
// */
|
|
func _sqlite3VdbeClearObject(tls *libc.TLS, db uintptr, p uintptr) {
|
|
var pNext, pSub uintptr
|
|
_, _ = pNext, pSub
|
|
if (*TVdbe)(unsafe.Pointer(p)).FaColName != 0 {
|
|
_releaseMemArray(tls, (*TVdbe)(unsafe.Pointer(p)).FaColName, libc.Int32FromUint16((*TVdbe)(unsafe.Pointer(p)).FnResAlloc)*int32(COLNAME_N))
|
|
_sqlite3DbNNFreeNN(tls, db, (*TVdbe)(unsafe.Pointer(p)).FaColName)
|
|
}
|
|
pSub = (*TVdbe)(unsafe.Pointer(p)).FpProgram
|
|
for {
|
|
if !(pSub != 0) {
|
|
break
|
|
}
|
|
pNext = (*TSubProgram)(unsafe.Pointer(pSub)).FpNext
|
|
_vdbeFreeOpArray(tls, db, (*TSubProgram)(unsafe.Pointer(pSub)).FaOp, (*TSubProgram)(unsafe.Pointer(pSub)).FnOp)
|
|
_sqlite3DbFree(tls, db, pSub)
|
|
goto _1
|
|
_1:
|
|
;
|
|
pSub = pNext
|
|
}
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FeVdbeState) != VDBE_INIT_STATE {
|
|
_releaseMemArray(tls, (*TVdbe)(unsafe.Pointer(p)).FaVar, int32((*TVdbe)(unsafe.Pointer(p)).FnVar))
|
|
if (*TVdbe)(unsafe.Pointer(p)).FpVList != 0 {
|
|
_sqlite3DbNNFreeNN(tls, db, (*TVdbe)(unsafe.Pointer(p)).FpVList)
|
|
}
|
|
if (*TVdbe)(unsafe.Pointer(p)).FpFree != 0 {
|
|
_sqlite3DbNNFreeNN(tls, db, (*TVdbe)(unsafe.Pointer(p)).FpFree)
|
|
}
|
|
}
|
|
_vdbeFreeOpArray(tls, db, (*TVdbe)(unsafe.Pointer(p)).FaOp, (*TVdbe)(unsafe.Pointer(p)).FnOp)
|
|
if (*TVdbe)(unsafe.Pointer(p)).FzSql != 0 {
|
|
_sqlite3DbNNFreeNN(tls, db, (*TVdbe)(unsafe.Pointer(p)).FzSql)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add a new OP_Explain opcode.
|
|
// **
|
|
// ** If the bPush flag is true, then make this opcode the parent for
|
|
// ** subsequent Explains until sqlite3VdbeExplainPop() is called.
|
|
// */
|
|
func _sqlite3VdbeExplain(tls *libc.TLS, pParse uintptr, bPush Tu8, zFmt uintptr, va uintptr) (r int32) {
|
|
var addr, iThis int32
|
|
var ap Tva_list
|
|
var v, zMsg uintptr
|
|
_, _, _, _, _ = addr, ap, iThis, v, zMsg
|
|
addr = 0
|
|
/* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
|
|
** But omit them (for performance) during production builds */
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).Fexplain) == int32(2) || libc.Bool(0 != 0) {
|
|
ap = va
|
|
zMsg = _sqlite3VMPrintf(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, zFmt, ap)
|
|
_ = ap
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
iThis = (*TVdbe)(unsafe.Pointer(v)).FnOp
|
|
addr = _sqlite3VdbeAddOp4(tls, v, int32(OP_Explain), iThis, (*TParse)(unsafe.Pointer(pParse)).FaddrExplain, 0, zMsg, -int32(7))
|
|
if bPush != 0 {
|
|
(*TParse)(unsafe.Pointer(pParse)).FaddrExplain = iThis
|
|
}
|
|
}
|
|
return addr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Clean up and delete a VDBE after execution. Return an integer which is
|
|
// ** the result code. Write any error message text into *pzErrMsg.
|
|
// */
|
|
func _sqlite3VdbeFinalize(tls *libc.TLS, p uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
rc = SQLITE_OK
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FeVdbeState) >= int32(VDBE_READY_STATE) {
|
|
rc = _sqlite3VdbeReset(tls, p)
|
|
}
|
|
_sqlite3VdbeDelete(tls, p)
|
|
return rc
|
|
}
|
|
|
|
func _sqlite3VdbeIntValue(tls *libc.TLS, pMem uintptr) (r Ti64) {
|
|
var flags int32
|
|
_ = flags
|
|
flags = libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)
|
|
if flags&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
return *(*Ti64)(unsafe.Pointer(pMem))
|
|
} else {
|
|
if flags&int32(MEM_Real) != 0 {
|
|
return _sqlite3RealToI64(tls, *(*float64)(unsafe.Pointer(pMem)))
|
|
} else {
|
|
if flags&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Blob)) != 0 && (*TMem)(unsafe.Pointer(pMem)).Fz != uintptr(0) {
|
|
return _memIntValue(tls, pMem)
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The MEM structure is already a MEM_Real or MEM_IntReal. Try to
|
|
// ** make it a MEM_Int if we can.
|
|
// */
|
|
func _sqlite3VdbeIntegerAffinity(tls *libc.TLS, pMem uintptr) {
|
|
var ix Ti64
|
|
_ = ix
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_IntReal) != 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_Int))
|
|
} else {
|
|
ix = _sqlite3RealToI64(tls, *(*float64)(unsafe.Pointer(pMem)))
|
|
/* Only mark the value as an integer if
|
|
**
|
|
** (1) the round-trip conversion real->int->real is a no-op, and
|
|
** (2) The integer is neither the largest nor the smallest
|
|
** possible integer (ticket #3922)
|
|
**
|
|
** The second and third terms in the following conditional enforces
|
|
** the second condition under the assumption that addition overflow causes
|
|
** values to wrap around.
|
|
*/
|
|
if *(*float64)(unsafe.Pointer(pMem)) == float64(ix) && ix > int64(-libc.Int32FromInt32(1))-(libc.Int64FromUint32(0xffffffff)|libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32)) && ix < libc.Int64FromUint32(0xffffffff)|libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32) {
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = ix
|
|
(*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))
|
|
}
|
|
}
|
|
}
|
|
|
|
func _sqlite3VdbeMemFromBtreeZeroOffset(tls *libc.TLS, pCur uintptr, amt Tu32, pMem uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc int32
|
|
var _ /* available at bp+0 */ Tu32
|
|
_ = rc
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0) /* Number of bytes available on the local btree page */
|
|
rc = SQLITE_OK /* Return code */
|
|
/* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
|
|
** that both the BtShared and database handle mutexes are held. */
|
|
(*TMem)(unsafe.Pointer(pMem)).Fz = _sqlite3BtreePayloadFetch(tls, pCur, bp)
|
|
if amt <= **(**Tu32)(__ccgo_up(bp)) {
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Blob) | libc.Int32FromInt32(MEM_Ephem))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fn = libc.Int32FromUint32(amt)
|
|
} else {
|
|
rc = _sqlite3VdbeMemFromBtree(tls, pCur, uint32(0), amt, pMem)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert pMem to type integer. Invalidate any prior representations.
|
|
// */
|
|
func _sqlite3VdbeMemIntegerify(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = _sqlite3VdbeIntValue(tls, pMem)
|
|
(*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))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make sure the given Mem is \u0000 terminated.
|
|
// */
|
|
func _sqlite3VdbeMemNulTerminate(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Term)|libc.Int32FromInt32(MEM_Str)) != int32(MEM_Str) {
|
|
return SQLITE_OK /* Nothing to do */
|
|
} else {
|
|
return _vdbeMemAddTerminator(tls, pMem)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert pMem so that it is of type MEM_Real.
|
|
// ** Invalidate any prior representations.
|
|
// */
|
|
func _sqlite3VdbeMemRealify(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
*(*float64)(unsafe.Pointer(pMem)) = _sqlite3VdbeRealValue(tls, pMem)
|
|
(*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))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Release any memory resources held by the Mem. Both the memory that is
|
|
// ** free by Mem.xDel and the Mem.zMalloc allocation are freed.
|
|
// **
|
|
// ** Use this routine prior to clean up prior to abandoning a Mem, or to
|
|
// ** reset a Mem back to its minimum memory utilization.
|
|
// **
|
|
// ** Use sqlite3VdbeMemSetNull() to release just the Mem.xDel space
|
|
// ** prior to inserting new content into the Mem.
|
|
// */
|
|
func _sqlite3VdbeMemRelease(tls *libc.TLS, p uintptr) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_Agg)|libc.Int32FromInt32(MEM_Dyn)) != 0 || (*TMem)(unsafe.Pointer(p)).FszMalloc != 0 {
|
|
_vdbeMemClear(tls, p)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete any previous value and set the value stored in *pMem to val,
|
|
// ** manifest type INTEGER.
|
|
// */
|
|
func _sqlite3VdbeMemSetInt64(tls *libc.TLS, pMem uintptr, val Ti64) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Agg)|libc.Int32FromInt32(MEM_Dyn)) != 0 {
|
|
_vdbeReleaseAndSetInt64(tls, pMem, val)
|
|
} else {
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = val
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Int)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete any previous value and set the value stored in *pMem to NULL.
|
|
// **
|
|
// ** This routine calls the Mem.xDel destructor to dispose of values that
|
|
// ** require the destructor. But it preserves the Mem.zMalloc memory allocation.
|
|
// ** To free all resources, use sqlite3VdbeMemRelease(), which both calls this
|
|
// ** routine to invoke the destructor and deallocates Mem.zMalloc.
|
|
// **
|
|
// ** Use this routine to reset the Mem prior to insert a new value.
|
|
// **
|
|
// ** Use sqlite3VdbeMemRelease() to complete erase the Mem prior to abandoning it.
|
|
// */
|
|
func _sqlite3VdbeMemSetNull(tls *libc.TLS, pMem uintptr) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Agg)|libc.Int32FromInt32(MEM_Dyn)) != 0 {
|
|
_vdbeMemClearExternAndSetNull(tls, pMem)
|
|
} else {
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Null)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete any previous value and set the value of pMem to be an
|
|
// ** empty boolean index.
|
|
// **
|
|
// ** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation
|
|
// ** error occurs.
|
|
// */
|
|
func _sqlite3VdbeMemSetRowSet(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
var db, p uintptr
|
|
_, _ = db, p
|
|
db = (*TMem)(unsafe.Pointer(pMem)).Fdb
|
|
_sqlite3VdbeMemRelease(tls, pMem)
|
|
p = _sqlite3RowSetInit(tls, db)
|
|
if p == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TMem)(unsafe.Pointer(pMem)).Fz = p
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Blob) | libc.Int32FromInt32(MEM_Dyn))
|
|
(*TMem)(unsafe.Pointer(pMem)).FxDel = __ccgo_fp(_sqlite3RowSetDelete)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete any previous value and set the value to be a BLOB of length
|
|
// ** n containing all zeros.
|
|
// */
|
|
func _sqlite3VdbeMemSetZeroBlob(tls *libc.TLS, pMem uintptr, n int32) {
|
|
_sqlite3VdbeMemRelease(tls, pMem)
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Blob) | libc.Int32FromInt32(MEM_Zero))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fn = 0
|
|
if n < 0 {
|
|
n = 0
|
|
}
|
|
*(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(pMem)).Fu)) = n
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = uint8(SQLITE_UTF8)
|
|
(*TMem)(unsafe.Pointer(pMem)).Fz = uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the best representation of pMem that we can get into a
|
|
// ** double. If pMem is already a double or an integer, return its
|
|
// ** value. If it is a string or blob, try to convert it to a double.
|
|
// ** If it is a NULL, return 0.0.
|
|
// */
|
|
func _sqlite3VdbeRealValue(tls *libc.TLS, pMem uintptr) (r float64) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Real) != 0 {
|
|
return *(*float64)(unsafe.Pointer(pMem))
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
return float64(*(*Ti64)(unsafe.Pointer(pMem)))
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Blob)) != 0 {
|
|
return _sqlite3MemRealValueNoRC(tls, pMem)
|
|
} else {
|
|
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
|
return libc.Float64FromInt32(0)
|
|
}
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Clean up a VDBE after execution but do not delete the VDBE just yet.
|
|
// ** Write any error messages into *pzErrMsg. Return the result code.
|
|
// **
|
|
// ** After this routine is run, the VDBE should be ready to be executed
|
|
// ** again.
|
|
// **
|
|
// ** To look at it another way, this routine resets the state of the
|
|
// ** virtual machine from VDBE_RUN_STATE or VDBE_HALT_STATE back to
|
|
// ** VDBE_READY_STATE.
|
|
// */
|
|
func _sqlite3VdbeReset(tls *libc.TLS, p uintptr) (r int32) {
|
|
var db uintptr
|
|
_ = db
|
|
db = (*TVdbe)(unsafe.Pointer(p)).Fdb
|
|
/* If the VM did not run to completion or if it encountered an
|
|
** error, then it might not have been halted properly. So halt
|
|
** it now.
|
|
*/
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FeVdbeState) == int32(VDBE_RUN_STATE) {
|
|
_sqlite3VdbeHalt(tls, p)
|
|
}
|
|
/* If the VDBE has been run even partially, then transfer the error code
|
|
** and error message from the VDBE into the main database structure. But
|
|
** if the VDBE has just been set to run but has not actually executed any
|
|
** instructions yet, leave the main database error information unchanged.
|
|
*/
|
|
if (*TVdbe)(unsafe.Pointer(p)).Fpc >= 0 {
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FpErr != 0 || (*TVdbe)(unsafe.Pointer(p)).FzErrMsg != 0 {
|
|
_sqlite3VdbeTransferError(tls, p)
|
|
} else {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FerrCode = (*TVdbe)(unsafe.Pointer(p)).Frc
|
|
}
|
|
}
|
|
/* Reset register contents and reclaim error message memory.
|
|
*/
|
|
if (*TVdbe)(unsafe.Pointer(p)).FzErrMsg != 0 {
|
|
_sqlite3DbFree(tls, db, (*TVdbe)(unsafe.Pointer(p)).FzErrMsg)
|
|
(*TVdbe)(unsafe.Pointer(p)).FzErrMsg = uintptr(0)
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FpResultRow = uintptr(0)
|
|
/* Save profiling information from this VDBE run.
|
|
*/
|
|
return (*TVdbe)(unsafe.Pointer(p)).Frc & (*Tsqlite3)(unsafe.Pointer(db)).FerrMask
|
|
}
|
|
|
|
func _sqlite3VdbeSerialGet(tls *libc.TLS, buf uintptr, serial_type Tu32, pMem uintptr) {
|
|
switch serial_type {
|
|
case uint32(10): /* Internal use only: NULL with virtual table
|
|
** UPDATE no-change flag set */
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Null) | libc.Int32FromInt32(MEM_Zero))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fn = 0
|
|
*(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(pMem)).Fu)) = 0
|
|
return
|
|
case uint32(11): /* Reserved for future use */
|
|
fallthrough
|
|
case uint32(0): /* Null */
|
|
/* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Null)
|
|
return
|
|
case uint32(1):
|
|
/* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement
|
|
** integer. */
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = int64(libc.Int8FromUint8(**(**uint8)(__ccgo_up(buf))))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Int)
|
|
return
|
|
case uint32(2): /* 2-byte signed integer */
|
|
/* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit
|
|
** twos-complement integer. */
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = int64(libc.Int32FromInt32(256)*int32(libc.Int8FromUint8(**(**uint8)(__ccgo_up(buf)))) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + 1))))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Int)
|
|
return
|
|
case uint32(3): /* 3-byte signed integer */
|
|
/* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit
|
|
** twos-complement integer. */
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = int64(libc.Int32FromInt32(65536)*int32(libc.Int8FromUint8(**(**uint8)(__ccgo_up(buf)))) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + 1)))<<libc.Int32FromInt32(8) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + 2))))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Int)
|
|
return
|
|
case uint32(4): /* 4-byte signed integer */
|
|
/* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
|
|
** twos-complement integer. */
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = int64(libc.Int32FromInt32(16777216)*int32(libc.Int8FromUint8(**(**uint8)(__ccgo_up(buf)))) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + 1)))<<libc.Int32FromInt32(16) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + 2)))<<libc.Int32FromInt32(8) | libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + 3))))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Int)
|
|
return
|
|
case uint32(5): /* 6-byte signed integer */
|
|
/* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit
|
|
** twos-complement integer. */
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = libc.Int64FromUint32(uint32(**(**uint8)(__ccgo_up(buf + libc.UintptrFromInt32(2))))<<libc.Int32FromInt32(24)|libc.Uint32FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + libc.UintptrFromInt32(2) + 1)))<<libc.Int32FromInt32(16))|libc.Uint32FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + libc.UintptrFromInt32(2) + 2)))<<libc.Int32FromInt32(8))|uint32(**(**uint8)(__ccgo_up(buf + libc.UintptrFromInt32(2) + 3)))) + libc.Int64FromInt32(1)<<libc.Int32FromInt32(32)*int64(libc.Int32FromInt32(256)*int32(libc.Int8FromUint8(**(**uint8)(__ccgo_up(buf))))|libc.Int32FromUint8(**(**uint8)(__ccgo_up(buf + 1))))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Int)
|
|
return
|
|
case uint32(6): /* 8-byte signed integer */
|
|
fallthrough
|
|
case uint32(7): /* IEEE floating point */
|
|
/* These use local variables, so do them in a separate routine
|
|
** to avoid having to move the frame pointer in the common case */
|
|
_serialGet(tls, buf, serial_type, pMem)
|
|
return
|
|
case uint32(8): /* Integer 0 */
|
|
fallthrough
|
|
case uint32(9): /* Integer 1 */
|
|
/* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */
|
|
/* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = libc.Int64FromUint32(serial_type - uint32(8))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(MEM_Int)
|
|
return
|
|
default:
|
|
(*TMem)(unsafe.Pointer(pMem)).Fz = buf
|
|
(*TMem)(unsafe.Pointer(pMem)).Fn = libc.Int32FromUint32((serial_type - uint32(12)) / uint32(2))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = _aFlag[serial_type&uint32(1)]
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Remember the SQL string for a prepared statement.
|
|
// */
|
|
func _sqlite3VdbeSetSql(tls *libc.TLS, p uintptr, z uintptr, n int32, prepFlags Tu8) {
|
|
if p == uintptr(0) {
|
|
return
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FprepFlags = prepFlags
|
|
if libc.Int32FromUint8(prepFlags)&int32(SQLITE_PREPARE_SAVESQL) == 0 {
|
|
(*TVdbe)(unsafe.Pointer(p)).Fexpmask = uint32(0)
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FzSql = _sqlite3DbStrNDup(tls, (*TVdbe)(unsafe.Pointer(p)).Fdb, z, libc.Uint64FromInt32(n))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the previous opcode is an OP_Column that delivers results
|
|
// ** into register iDest, then add the OPFLAG_TYPEOFARG flag to that
|
|
// ** opcode.
|
|
// */
|
|
func _sqlite3VdbeTypeofColumn(tls *libc.TLS, p uintptr, iDest int32) {
|
|
var pOp, v1 uintptr
|
|
_, _ = pOp, v1
|
|
pOp = _sqlite3VdbeGetLastOp(tls, p)
|
|
if (*TVdbeOp)(unsafe.Pointer(pOp)).Fp3 == iDest && libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode) == int32(OP_Column) {
|
|
v1 = pOp + 2
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(OPFLAG_TYPEOFARG))
|
|
}
|
|
}
|
|
|
|
func _sqlite3ViewGetColumnNames(tls *libc.TLS, pParse uintptr, pTable uintptr) (r int32) {
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTable)).FeTabType) == libc.Int32FromInt32(TABTYP_VTAB)) && int32((*TTable)(unsafe.Pointer(pTable)).FnCol) > 0 {
|
|
return 0
|
|
}
|
|
return _viewGetColumnNames(tls, pParse, pTable)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Return the value to pass to a sqlite3_wal_hook callback, the
|
|
// ** number of frames in the WAL at the point of the last commit since
|
|
// ** sqlite3WalCallback() was called. If no commits have occurred since
|
|
// ** the last call, then return 0.
|
|
// */
|
|
func _sqlite3WalCallback(tls *libc.TLS, pWal uintptr) (r int32) {
|
|
var ret Tu32
|
|
_ = ret
|
|
ret = uint32(0)
|
|
if pWal != 0 {
|
|
ret = (*TWal)(unsafe.Pointer(pWal)).FiCallback
|
|
(*TWal)(unsafe.Pointer(pWal)).FiCallback = uint32(0)
|
|
}
|
|
return libc.Int32FromUint32(ret)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close a connection to a log file.
|
|
// */
|
|
func _sqlite3WalClose(tls *libc.TLS, pWal uintptr, db uintptr, sync_flags int32, nBuf int32, zBuf uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var isDelete, rc, v1 int32
|
|
var v2 bool
|
|
var _ /* bPersist at bp+0 */ int32
|
|
_, _, _, _ = isDelete, rc, v1, v2
|
|
rc = SQLITE_OK
|
|
if pWal != 0 {
|
|
isDelete = 0 /* True to unlink wal and wal-index files */
|
|
/* If an EXCLUSIVE lock can be obtained on the database file (using the
|
|
** ordinary, rollback-mode locking methods, this guarantees that the
|
|
** connection associated with this log file is the only connection to
|
|
** the database. In this case checkpoint the database and unlink both
|
|
** the wal and wal-index files.
|
|
**
|
|
** The EXCLUSIVE lock is not released before returning.
|
|
*/
|
|
if v2 = zBuf != uintptr(0); v2 {
|
|
v1 = _sqlite3OsLock(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, int32(SQLITE_LOCK_EXCLUSIVE))
|
|
rc = v1
|
|
}
|
|
if v2 && SQLITE_OK == v1 {
|
|
if libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FexclusiveMode) == WAL_NORMAL_MODE {
|
|
(*TWal)(unsafe.Pointer(pWal)).FexclusiveMode = uint8(WAL_EXCLUSIVE_MODE)
|
|
}
|
|
rc = _sqlite3WalCheckpoint(tls, pWal, db, SQLITE_CHECKPOINT_PASSIVE, uintptr(0), uintptr(0), sync_flags, nBuf, zBuf, uintptr(0), uintptr(0))
|
|
if rc == SQLITE_OK {
|
|
**(**int32)(__ccgo_up(bp)) = -int32(1)
|
|
_sqlite3OsFileControlHint(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, int32(SQLITE_FCNTL_PERSIST_WAL), bp)
|
|
if **(**int32)(__ccgo_up(bp)) != int32(1) {
|
|
/* Try to delete the WAL file if the checkpoint completed and
|
|
** fsynced (rc==SQLITE_OK) and if we are not in persistent-wal
|
|
** mode (!bPersist) */
|
|
isDelete = int32(1)
|
|
} else {
|
|
if (*TWal)(unsafe.Pointer(pWal)).FmxWalSize >= 0 {
|
|
/* Try to truncate the WAL file to zero bytes if the checkpoint
|
|
** completed and fsynced (rc==SQLITE_OK) and we are in persistent
|
|
** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
|
|
** non-negative value (pWal->mxWalSize>=0). Note that we truncate
|
|
** to zero bytes as truncating to the journal_size_limit might
|
|
** leave a corrupt WAL file on disk. */
|
|
_walLimitSize(tls, pWal, 0)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_walIndexClose(tls, pWal, isDelete)
|
|
_sqlite3OsClose(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd)
|
|
if isDelete != 0 {
|
|
_sqlite3BeginBenignMalloc(tls)
|
|
_sqlite3OsDelete(tls, (*TWal)(unsafe.Pointer(pWal)).FpVfs, (*TWal)(unsafe.Pointer(pWal)).FzWalName, 0)
|
|
_sqlite3EndBenignMalloc(tls)
|
|
}
|
|
Xsqlite3_free(tls, (*TWal)(unsafe.Pointer(pWal)).FapWiData)
|
|
Xsqlite3_free(tls, pWal)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called to change the WAL subsystem into or out
|
|
// ** of locking_mode=EXCLUSIVE.
|
|
// **
|
|
// ** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
|
|
// ** into locking_mode=NORMAL. This means that we must acquire a lock
|
|
// ** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL
|
|
// ** or if the acquisition of the lock fails, then return 0. If the
|
|
// ** transition out of exclusive-mode is successful, return 1. This
|
|
// ** operation must occur while the pager is still holding the exclusive
|
|
// ** lock on the main database file.
|
|
// **
|
|
// ** If op is one, then change from locking_mode=NORMAL into
|
|
// ** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
|
|
// ** be released. Return 1 if the transition is made and 0 if the
|
|
// ** WAL is already in exclusive-locking mode - meaning that this
|
|
// ** routine is a no-op. The pager must already hold the exclusive lock
|
|
// ** on the main database file before invoking this operation.
|
|
// **
|
|
// ** If op is negative, then do a dry-run of the op==1 case but do
|
|
// ** not actually change anything. The pager uses this to see if it
|
|
// ** should acquire the database exclusive lock prior to invoking
|
|
// ** the op==1 case.
|
|
// */
|
|
func _sqlite3WalExclusiveMode(tls *libc.TLS, pWal uintptr, op int32) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
/* pWal->readLock is usually set, but might be -1 if there was a
|
|
** prior error while attempting to acquire are read-lock. This cannot
|
|
** happen if the connection is actually in exclusive mode (as no xShmLock
|
|
** locks are taken in this case). Nor should the pager attempt to
|
|
** upgrade to exclusive-mode following such an error.
|
|
*/
|
|
if op == 0 {
|
|
if libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FexclusiveMode) != WAL_NORMAL_MODE {
|
|
(*TWal)(unsafe.Pointer(pWal)).FexclusiveMode = uint8(WAL_NORMAL_MODE)
|
|
if _walLockShared(tls, pWal, int32(3)+int32((*TWal)(unsafe.Pointer(pWal)).FreadLock)) != SQLITE_OK {
|
|
(*TWal)(unsafe.Pointer(pWal)).FexclusiveMode = uint8(WAL_EXCLUSIVE_MODE)
|
|
}
|
|
rc = libc.BoolInt32(libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FexclusiveMode) == WAL_NORMAL_MODE)
|
|
} else {
|
|
/* Already in locking_mode=NORMAL */
|
|
rc = 0
|
|
}
|
|
} else {
|
|
if op > 0 {
|
|
_walUnlockShared(tls, pWal, int32(3)+int32((*TWal)(unsafe.Pointer(pWal)).FreadLock))
|
|
(*TWal)(unsafe.Pointer(pWal)).FexclusiveMode = uint8(WAL_EXCLUSIVE_MODE)
|
|
rc = int32(1)
|
|
} else {
|
|
rc = libc.BoolInt32(libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FexclusiveMode) == WAL_NORMAL_MODE)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the argument is non-NULL and the WAL module is using
|
|
// ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
|
|
// ** WAL module is using shared-memory, return false.
|
|
// */
|
|
func _sqlite3WalHeapMemory(tls *libc.TLS, pWal uintptr) (r int32) {
|
|
return libc.BoolInt32(pWal != 0 && libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FexclusiveMode) == int32(WAL_HEAPMEMORY_MODE))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read the contents of frame iRead from the wal file into buffer pOut
|
|
// ** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
|
|
// ** error code otherwise.
|
|
// */
|
|
func _sqlite3WalReadFrame(tls *libc.TLS, pWal uintptr, iRead Tu32, nOut int32, pOut uintptr) (r int32) {
|
|
var iOffset Ti64
|
|
var sz, v1 int32
|
|
_, _, _ = iOffset, sz, v1
|
|
sz = libc.Int32FromUint16((*TWal)(unsafe.Pointer(pWal)).Fhdr.FszPage)
|
|
sz = sz&int32(0xfe00) + sz&int32(0x0001)<<int32(16)
|
|
iOffset = int64(WAL_HDRSIZE) + libc.Int64FromUint32(iRead-libc.Uint32FromInt32(1))*int64(sz+libc.Int32FromInt32(WAL_FRAME_HDRSIZE)) + int64(WAL_FRAME_HDRSIZE)
|
|
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
|
|
if nOut > sz {
|
|
v1 = sz
|
|
} else {
|
|
v1 = nOut
|
|
}
|
|
return _sqlite3OsRead(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd, pOut, v1, iOffset)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
|
|
// ** variable so that older snapshots can be accessed. To do this, loop
|
|
// ** through all wal frames from nBackfillAttempted to (nBackfill+1),
|
|
// ** comparing their content to the corresponding page with the database
|
|
// ** file, if any. Set nBackfillAttempted to the frame number of the
|
|
// ** first frame for which the wal file content matches the db file.
|
|
// **
|
|
// ** This is only really safe if the file-system is such that any page
|
|
// ** writes made by earlier checkpointers were atomic operations, which
|
|
// ** is not always true. It is also possible that nBackfillAttempted
|
|
// ** may be left set to a value larger than expected, if a wal frame
|
|
// ** contains content that duplicate of an earlier version of the same
|
|
// ** page.
|
|
// **
|
|
// ** SQLITE_OK is returned if successful, or an SQLite error code if an
|
|
// ** error occurs. It is not an error if nBackfillAttempted cannot be
|
|
// ** decreased at all.
|
|
// */
|
|
func _sqlite3WalSnapshotRecover(tls *libc.TLS, pWal uintptr) (r int32) {
|
|
var pBuf1, pBuf2 uintptr
|
|
var rc int32
|
|
_, _, _ = pBuf1, pBuf2, rc
|
|
rc = _walLockExclusive(tls, pWal, int32(WAL_CKPT_LOCK), int32(1))
|
|
if rc == SQLITE_OK {
|
|
pBuf1 = Xsqlite3_malloc(tls, libc.Int32FromUint32((*TWal)(unsafe.Pointer(pWal)).FszPage))
|
|
pBuf2 = Xsqlite3_malloc(tls, libc.Int32FromUint32((*TWal)(unsafe.Pointer(pWal)).FszPage))
|
|
if pBuf1 == uintptr(0) || pBuf2 == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
} else {
|
|
(*TWal)(unsafe.Pointer(pWal)).FckptLock = uint8(1)
|
|
rc = _walSnapshotRecover(tls, pWal, pBuf1, pBuf2)
|
|
(*TWal)(unsafe.Pointer(pWal)).FckptLock = uint8(0)
|
|
}
|
|
Xsqlite3_free(tls, pBuf1)
|
|
Xsqlite3_free(tls, pBuf2)
|
|
_walUnlockExclusive(tls, pWal, int32(WAL_CKPT_LOCK), int32(1))
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walk all expressions associated with SELECT statement p. Do
|
|
// ** not invoke the SELECT callback on p, but do (of course) invoke
|
|
// ** any expr callbacks and SELECT callbacks that come from subqueries.
|
|
// ** Return WRC_Abort or WRC_Continue.
|
|
// */
|
|
func _sqlite3WalkSelectExpr(tls *libc.TLS, pWalker uintptr, p uintptr) (r int32) {
|
|
var pParse, v1 uintptr
|
|
var rc int32
|
|
var v2 bool
|
|
_, _, _, _ = pParse, rc, v1, v2
|
|
if _sqlite3WalkExprList(tls, pWalker, (*TSelect)(unsafe.Pointer(p)).FpEList) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
if _sqlite3WalkExpr(tls, pWalker, (*TSelect)(unsafe.Pointer(p)).FpWhere) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
if _sqlite3WalkExprList(tls, pWalker, (*TSelect)(unsafe.Pointer(p)).FpGroupBy) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
if _sqlite3WalkExpr(tls, pWalker, (*TSelect)(unsafe.Pointer(p)).FpHaving) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
if _sqlite3WalkExprList(tls, pWalker, (*TSelect)(unsafe.Pointer(p)).FpOrderBy) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
if _sqlite3WalkExpr(tls, pWalker, (*TSelect)(unsafe.Pointer(p)).FpLimit) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(p)).FpWinDefn != 0 {
|
|
if v2 = (*TWalker)(unsafe.Pointer(pWalker)).FxSelectCallback2 == __ccgo_fp(_sqlite3WalkWinDefnDummyCallback); !v2 {
|
|
v1 = (*TWalker)(unsafe.Pointer(pWalker)).FpParse
|
|
pParse = v1
|
|
}
|
|
if v2 || v1 != uintptr(0) && libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) || (*TWalker)(unsafe.Pointer(pWalker)).FxSelectCallback2 == __ccgo_fp(_sqlite3SelectPopWith) {
|
|
/* The following may return WRC_Abort if there are unresolvable
|
|
** symbols (e.g. a table that does not exist) in a window definition. */
|
|
rc = _walkWindowList(tls, pWalker, (*TSelect)(unsafe.Pointer(p)).FpWinDefn, 0)
|
|
return rc
|
|
}
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
|
|
// ** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
|
|
// ** was defined at compile-time. If it is not a no-op, a single OP_Explain
|
|
// ** opcode is added to the output to describe the table scan strategy in pLevel.
|
|
// **
|
|
// ** If an OP_Explain opcode is added to the VM, its address is returned.
|
|
// ** Otherwise, if no OP_Explain is coded, zero is returned.
|
|
// */
|
|
func _sqlite3WhereExplainOneScan(tls *libc.TLS, pParse uintptr, pTabList uintptr, pLevel uintptr, wctrlFlags Tu16) (r int32) {
|
|
var addr, ret int32
|
|
var v, v1 uintptr
|
|
_, _, _, _ = addr, ret, v, v1
|
|
ret = 0
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0 {
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpToplevel
|
|
} else {
|
|
v1 = pParse
|
|
}
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(v1)).Fexplain) == int32(2) || libc.Bool(0 != 0) {
|
|
if (*TWhereLoop)(unsafe.Pointer((*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop)).FwsFlags&uint32(WHERE_MULTI_OR) == uint32(0) && libc.Int32FromUint16(wctrlFlags)&int32(WHERE_OR_SUBCLAUSE) == 0 {
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
addr = _sqlite3VdbeCurrentAddr(tls, v)
|
|
ret = _sqlite3VdbeAddOp3(tls, v, int32(OP_Explain), addr, (*TParse)(unsafe.Pointer(pParse)).FaddrExplain, int32((*TWhereLoop)(unsafe.Pointer((*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop)).FrRun))
|
|
_sqlite3WhereAddExplainText(tls, pParse, addr, pTabList, pLevel, wctrlFlags)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func _sqlite3WhereExprUsageNN(tls *libc.TLS, pMaskSet uintptr, p uintptr) (r TBitmask) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_COLUMN) && !((*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_FixedCol)) != libc.Uint32FromInt32(0)) {
|
|
return _sqlite3WhereGetMask(tls, pMaskSet, (*TExpr)(unsafe.Pointer(p)).FiTable)
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_TokenOnly)|libc.Int32FromInt32(EP_Leaf)) != uint32(0) {
|
|
return uint64(0)
|
|
}
|
|
}
|
|
return _sqlite3WhereExprUsageFull(tls, pMaskSet, p)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this
|
|
// ** WHERE clause returns outputs for DISTINCT processing.
|
|
// */
|
|
func _sqlite3WhereIsDistinct(tls *libc.TLS, pWInfo uintptr) (r int32) {
|
|
return libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FeDistinct)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine identifies subexpressions in the WHERE clause where
|
|
// ** each subexpression is separated by the AND operator or some other
|
|
// ** operator specified in the op parameter. The WhereClause structure
|
|
// ** is filled with pointers to subexpressions. For example:
|
|
// **
|
|
// ** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22)
|
|
// ** \________/ \_______________/ \________________/
|
|
// ** slot[0] slot[1] slot[2]
|
|
// **
|
|
// ** The original WHERE clause in pExpr is unaltered. All this routine
|
|
// ** does is make slot[] entries point to substructure within pExpr.
|
|
// **
|
|
// ** In the previous sentence and in the diagram, "slot[]" refers to
|
|
// ** the WhereClause.a[] array. The slot[] array grows as needed to contain
|
|
// ** all terms of the WHERE clause.
|
|
// */
|
|
func _sqlite3WhereSplit(tls *libc.TLS, pWC uintptr, pExpr uintptr, op Tu8) {
|
|
var pE2 uintptr
|
|
_ = pE2
|
|
pE2 = _sqlite3ExprSkipCollateAndLikely(tls, pExpr)
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).Fop = op
|
|
if pE2 == uintptr(0) {
|
|
return
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pE2)).Fop) != libc.Int32FromUint8(op) {
|
|
_whereClauseInsert(tls, pWC, pExpr, uint16(0))
|
|
} else {
|
|
_sqlite3WhereSplit(tls, pWC, (*TExpr)(unsafe.Pointer(pE2)).FpLeft, op)
|
|
_sqlite3WhereSplit(tls, pWC, (*TExpr)(unsafe.Pointer(pE2)).FpRight, op)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return 0 if the two window objects are identical, 1 if they are
|
|
// ** different, or 2 if it cannot be determined if the objects are identical
|
|
// ** or not. Identical window objects can be processed in a single scan.
|
|
// */
|
|
func _sqlite3WindowCompare(tls *libc.TLS, pParse uintptr, p1 uintptr, p2 uintptr, bFilter int32) (r int32) {
|
|
var res, v1 int32
|
|
_, _ = res, v1
|
|
if p1 == uintptr(0) || p2 == uintptr(0) {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(p1)).FeFrmType) != libc.Int32FromUint8((*TWindow)(unsafe.Pointer(p2)).FeFrmType) {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(p1)).FeStart) != libc.Int32FromUint8((*TWindow)(unsafe.Pointer(p2)).FeStart) {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(p1)).FeEnd) != libc.Int32FromUint8((*TWindow)(unsafe.Pointer(p2)).FeEnd) {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(p1)).FeExclude) != libc.Int32FromUint8((*TWindow)(unsafe.Pointer(p2)).FeExclude) {
|
|
return int32(1)
|
|
}
|
|
if _sqlite3ExprCompare(tls, pParse, (*TWindow)(unsafe.Pointer(p1)).FpStart, (*TWindow)(unsafe.Pointer(p2)).FpStart, -int32(1)) != 0 {
|
|
return int32(1)
|
|
}
|
|
if _sqlite3ExprCompare(tls, pParse, (*TWindow)(unsafe.Pointer(p1)).FpEnd, (*TWindow)(unsafe.Pointer(p2)).FpEnd, -int32(1)) != 0 {
|
|
return int32(1)
|
|
}
|
|
v1 = _sqlite3ExprListCompare(tls, (*TWindow)(unsafe.Pointer(p1)).FpPartition, (*TWindow)(unsafe.Pointer(p2)).FpPartition, -int32(1))
|
|
res = v1
|
|
if v1 != 0 {
|
|
return res
|
|
}
|
|
v1 = _sqlite3ExprListCompare(tls, (*TWindow)(unsafe.Pointer(p1)).FpOrderBy, (*TWindow)(unsafe.Pointer(p2)).FpOrderBy, -int32(1))
|
|
res = v1
|
|
if v1 != 0 {
|
|
return res
|
|
}
|
|
if bFilter != 0 {
|
|
v1 = _sqlite3ExprCompare(tls, pParse, (*TWindow)(unsafe.Pointer(p1)).FpFilter, (*TWindow)(unsafe.Pointer(p2)).FpFilter, -int32(1))
|
|
res = v1
|
|
if v1 != 0 {
|
|
return res
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** When rewriting a query, if the new subquery in the FROM clause
|
|
// ** contains TK_AGG_FUNCTION nodes that refer to an outer query,
|
|
// ** then we have to increase the Expr->op2 values of those nodes
|
|
// ** due to the extra subquery layer that was added.
|
|
// **
|
|
// ** See also the incrAggDepth() routine in resolve.c
|
|
// */
|
|
func _sqlite3WindowExtraAggFuncDepth(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AGG_FUNCTION) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop2) >= (*TWalker)(unsafe.Pointer(pWalker)).FwalkerDepth {
|
|
(*TExpr)(unsafe.Pointer(pExpr)).Fop2 = (*TExpr)(unsafe.Pointer(pExpr)).Fop2 + 1
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The argument expression is an PRECEDING or FOLLOWING offset. The
|
|
// ** value should be a non-negative integer. If the value is not a
|
|
// ** constant, change it to NULL. The fact that it is then a non-negative
|
|
// ** integer will be caught later. But it is important not to leave
|
|
// ** variable values in the expression tree.
|
|
// */
|
|
func _sqlite3WindowOffsetExpr(tls *libc.TLS, pParse uintptr, pExpr uintptr) (r uintptr) {
|
|
if 0 == _sqlite3ExprIsConstant(tls, uintptr(0), pExpr) {
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
_sqlite3RenameExprUnmap(tls, pParse, pExpr)
|
|
}
|
|
_sqlite3ExprDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pExpr)
|
|
pExpr = _sqlite3ExprAlloc(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, int32(TK_NULL), uintptr(0), 0)
|
|
}
|
|
return pExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** True if PRAGMA writable_schema is ON
|
|
// */
|
|
func _sqlite3WritableSchema(tls *libc.TLS, db uintptr) (r int32) {
|
|
return libc.BoolInt32((*Tsqlite3)(unsafe.Pointer(db)).Fflags&libc.Uint64FromInt32(libc.Int32FromInt32(SQLITE_WriteSchema)|libc.Int32FromInt32(SQLITE_Defensive)) == uint64(SQLITE_WriteSchema))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine translates a standard POSIX errno code into something
|
|
// ** useful to the clients of the sqlite3 functions. Specifically, it is
|
|
// ** intended to translate a variety of "try again" errors into SQLITE_BUSY
|
|
// ** and a variety of "please close the file descriptor NOW" errors into
|
|
// ** SQLITE_IOERR
|
|
// **
|
|
// ** Errors during initialization of locks, or file system support for locks,
|
|
// ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
|
|
// */
|
|
func _sqliteErrorFromPosixError(tls *libc.TLS, posixError int32, sqliteIOErr int32) (r int32) {
|
|
switch posixError {
|
|
case int32(EACCES):
|
|
fallthrough
|
|
case int32(EAGAIN):
|
|
fallthrough
|
|
case int32(ETIMEDOUT):
|
|
fallthrough
|
|
case int32(EBUSY):
|
|
fallthrough
|
|
case int32(EINTR):
|
|
fallthrough
|
|
case int32(ENOLCK):
|
|
/* random NFS retry error, unless during file system support
|
|
* introspection, in which it actually means what it says */
|
|
return int32(SQLITE_BUSY)
|
|
case int32(EPERM):
|
|
return int32(SQLITE_PERM)
|
|
default:
|
|
return sqliteIOErr
|
|
}
|
|
return r
|
|
}
|
|
|
|
func _statEof(tls *libc.TLS, pCursor uintptr) (r int32) {
|
|
var pCsr uintptr
|
|
_ = pCsr
|
|
pCsr = pCursor
|
|
return libc.Int32FromUint8((*TStatCursor)(unsafe.Pointer(pCsr)).FisEof)
|
|
}
|
|
|
|
func _statRowid(tls *libc.TLS, pCursor uintptr, pRowid uintptr) (r int32) {
|
|
var pCsr uintptr
|
|
_ = pCsr
|
|
pCsr = pCursor
|
|
**(**Tsqlite_int64)(__ccgo_up(pRowid)) = libc.Int64FromUint32((*TStatCursor)(unsafe.Pointer(pCsr)).FiPageno)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the pFile->lastErrno. Do this in a subroutine as that provides
|
|
// ** a convenient place to set a breakpoint.
|
|
// */
|
|
func _storeLastErrno(tls *libc.TLS, pFile uintptr, error1 int32) {
|
|
(*TunixFile)(unsafe.Pointer(pFile)).FlastErrno = error1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Buffer zStr contains nStr bytes of utf-8 encoded text. Return 1 if zStr
|
|
// ** contains character ch, or 0 if it does not.
|
|
// */
|
|
func _strContainsChar(tls *libc.TLS, zStr uintptr, nStr int32, ch Tu32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var tst Tu32
|
|
var zEnd, v2 uintptr
|
|
var v1 uint32
|
|
var _ /* z at bp+0 */ uintptr
|
|
_, _, _, _ = tst, zEnd, v1, v2
|
|
zEnd = zStr + uintptr(nStr)
|
|
**(**uintptr)(__ccgo_up(bp)) = zStr
|
|
for **(**uintptr)(__ccgo_up(bp)) < zEnd {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) < int32(0x80) {
|
|
v2 = **(**uintptr)(__ccgo_up(bp))
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + 1
|
|
v1 = uint32(**(**Tu8)(__ccgo_up(v2)))
|
|
} else {
|
|
v1 = _sqlite3Utf8Read(tls, bp)
|
|
}
|
|
tst = v1
|
|
if tst == ch {
|
|
return int32(1)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append a record of the current state of page pPg to the sub-journal.
|
|
// **
|
|
// ** If successful, set the bit corresponding to pPg->pgno in the bitvecs
|
|
// ** for all open savepoints before returning.
|
|
// **
|
|
// ** This function returns SQLITE_OK if everything is successful, an IO
|
|
// ** error code if the attempt to write to the sub-journal fails, or
|
|
// ** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint
|
|
// ** bitvec.
|
|
// */
|
|
func _subjournalPage(tls *libc.TLS, pPg uintptr) (r int32) {
|
|
var offset Ti64
|
|
var pData, pData2, pPager uintptr
|
|
var rc int32
|
|
_, _, _, _, _ = offset, pData, pData2, pPager, rc
|
|
rc = SQLITE_OK
|
|
pPager = (*TPgHdr)(unsafe.Pointer(pPg)).FpPager
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) != int32(PAGER_JOURNALMODE_OFF) {
|
|
/* Open the sub-journal, if it has not already been opened */
|
|
rc = _openSubJournal(tls, pPager)
|
|
/* If the sub-journal was opened successfully (or was already open),
|
|
** write the journal record into the file. */
|
|
if rc == SQLITE_OK {
|
|
pData = (*TPgHdr)(unsafe.Pointer(pPg)).FpData
|
|
offset = libc.Int64FromUint32((*TPager)(unsafe.Pointer(pPager)).FnSubRec) * (int64(4) + (*TPager)(unsafe.Pointer(pPager)).FpageSize)
|
|
pData2 = pData
|
|
rc = _write32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fsjfd, offset, (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno)
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3OsWrite(tls, (*TPager)(unsafe.Pointer(pPager)).Fsjfd, pData2, int32((*TPager)(unsafe.Pointer(pPager)).FpageSize), offset+int64(4))
|
|
}
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
(*TPager)(unsafe.Pointer(pPager)).FnSubRec = (*TPager)(unsafe.Pointer(pPager)).FnSubRec + 1
|
|
rc = _addToSavepointBitvecs(tls, pPager, (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* subtype(X)
|
|
// **
|
|
// ** Return the subtype of X
|
|
// */
|
|
func _subtypeFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
_ = argc
|
|
Xsqlite3_result_int(tls, context, libc.Int32FromUint32(Xsqlite3_value_subtype(tls, **(**uintptr)(__ccgo_up(argv)))))
|
|
}
|
|
|
|
func _tabIsReadOnly(tls *libc.TLS, pParse uintptr, pTab uintptr) (r int32) {
|
|
var db uintptr
|
|
_ = db
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) {
|
|
return _vtabIsReadOnly(tls, pParse, pTab)
|
|
}
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&libc.Uint32FromInt32(libc.Int32FromInt32(TF_Readonly)|libc.Int32FromInt32(TF_Shadow)) == uint32(0) {
|
|
return 0
|
|
}
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_Readonly) != uint32(0) {
|
|
return libc.BoolInt32(_sqlite3WritableSchema(tls, db) == 0 && libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).Fnested) == 0)
|
|
}
|
|
return _sqlite3ReadOnlyShadowTables(tls, db)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The unicode() function. Return the integer unicode code-point value
|
|
// ** for the first character of the input string.
|
|
// */
|
|
func _unicodeFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var _ /* z at bp+0 */ uintptr
|
|
**(**uintptr)(__ccgo_up(bp)) = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
_ = argc
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 && **(**uint8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp)))) != 0 {
|
|
Xsqlite3_result_int(tls, context, libc.Int32FromUint32(_sqlite3Utf8Read(tls, bp)))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Helper functions to obtain and relinquish the global mutex. The
|
|
// ** global mutex is used to protect the unixInodeInfo objects used by
|
|
// ** this file, all of which may be shared by multiple threads.
|
|
// **
|
|
// ** Function unixMutexHeld() is used to assert() that the global mutex
|
|
// ** is held when required. This function is only used as part of assert()
|
|
// ** statements. e.g.
|
|
// **
|
|
// ** unixEnterMutex()
|
|
// ** assert( unixMutexHeld() );
|
|
// ** unixEnterLeave()
|
|
// **
|
|
// ** To prevent deadlock, the global unixBigLock must must be acquired
|
|
// ** before the unixInodeInfo.pLockMutex mutex, if both are held. It is
|
|
// ** OK to get the pLockMutex without holding unixBigLock first, but if
|
|
// ** that happens, the unixBigLock mutex must not be acquired until after
|
|
// ** pLockMutex is released.
|
|
// **
|
|
// ** OK: enter(unixBigLock), enter(pLockInfo)
|
|
// ** OK: enter(unixBigLock)
|
|
// ** OK: enter(pLockInfo)
|
|
// ** ERROR: enter(pLockInfo), enter(unixBigLock)
|
|
// */
|
|
var _unixBigLock = uintptr(0)
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close a file.
|
|
// */
|
|
func _unixClose(tls *libc.TLS, id uintptr) (r int32) {
|
|
var pFile, pInode uintptr
|
|
var rc int32
|
|
_, _, _ = pFile, pInode, rc
|
|
rc = SQLITE_OK
|
|
pFile = id
|
|
pInode = (*TunixFile)(unsafe.Pointer(pFile)).FpInode
|
|
_verifyDbFile(tls, pFile)
|
|
_unixUnlock(tls, id, NO_LOCK)
|
|
_unixEnterMutex(tls)
|
|
/* unixFile.pInode is always valid here. Otherwise, a different close
|
|
** routine (e.g. nolockClose()) would be called instead.
|
|
*/
|
|
Xsqlite3_mutex_enter(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
|
|
if (*TunixInodeInfo)(unsafe.Pointer(pInode)).FnLock != 0 {
|
|
/* If there are outstanding locks, do not actually close the file just
|
|
** yet because that would clear those locks. Instead, add the file
|
|
** descriptor to pInode->pUnused list. It will be automatically closed
|
|
** when the last lock is cleared.
|
|
*/
|
|
_setPendingFd(tls, pFile)
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
|
|
_releaseInodeInfo(tls, pFile)
|
|
rc = _closeUnixFile(tls, id)
|
|
_unixLeaveMutex(tls)
|
|
return rc
|
|
}
|
|
|
|
/************** End of the posix advisory lock implementation *****************
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
****************************** No-op Locking **********************************
|
|
**
|
|
** Of the various locking implementations available, this is by far the
|
|
** simplest: locking is ignored. No attempt is made to lock the database
|
|
** file for reading or writing.
|
|
**
|
|
** This locking mode is appropriate for use on read-only databases
|
|
** (ex: databases that are burned into CD-ROM, for example.) It can
|
|
** also be used if the application employs some external mechanism to
|
|
** prevent simultaneous access of the same database by two or more
|
|
** database connections. But there is a serious risk of database
|
|
** corruption if this locking mode is used in situations where multiple
|
|
** database connections are accessing the same database file at the same
|
|
** time and one or more of those connections are writing.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find the current time (in Universal Coordinated Time). Write the
|
|
// ** current time and date as a Julian Day number into *prNow and
|
|
// ** return 0. Return 1 if the time and date cannot be found.
|
|
// */
|
|
func _unixCurrentTime(tls *libc.TLS, NotUsed uintptr, prNow uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc int32
|
|
var _ /* i at bp+0 */ Tsqlite3_int64
|
|
_ = rc
|
|
**(**Tsqlite3_int64)(__ccgo_up(bp)) = 0
|
|
_ = NotUsed
|
|
rc = _unixCurrentTimeInt64(tls, uintptr(0), bp)
|
|
**(**float64)(__ccgo_up(prNow)) = float64(**(**Tsqlite3_int64)(__ccgo_up(bp))) / float64(8.64e+07)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the device characteristics for the file.
|
|
// **
|
|
// ** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
|
|
// ** However, that choice is controversial since technically the underlying
|
|
// ** file system does not always provide powersafe overwrites. (In other
|
|
// ** words, after a power-loss event, parts of the file that were never
|
|
// ** written might end up being altered.) However, non-PSOW behavior is very,
|
|
// ** very rare. And asserting PSOW makes a large reduction in the amount
|
|
// ** of required I/O for journaling, since a lot of padding is eliminated.
|
|
// ** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
|
|
// ** available to turn it off and URI query parameter available to turn it off.
|
|
// */
|
|
func _unixDeviceCharacteristics(tls *libc.TLS, id uintptr) (r int32) {
|
|
var pFd uintptr
|
|
_ = pFd
|
|
pFd = id
|
|
_setDeviceCharacteristics(tls, pFd)
|
|
return (*TunixFile)(unsafe.Pointer(pFd)).FdeviceCharacteristics
|
|
}
|
|
|
|
func _unixDlClose(tls *libc.TLS, NotUsed uintptr, pHandle uintptr) {
|
|
_ = NotUsed
|
|
libc.Xdlclose(tls, pHandle)
|
|
}
|
|
|
|
func _unixDlOpen(tls *libc.TLS, NotUsed uintptr, zFilename uintptr) (r uintptr) {
|
|
_ = NotUsed
|
|
return libc.Xdlopen(tls, zFilename, libc.Int32FromInt32(RTLD_NOW)|libc.Int32FromInt32(RTLD_GLOBAL))
|
|
}
|
|
|
|
func _unixDlSym(tls *libc.TLS, NotUsed uintptr, p uintptr, zSym uintptr) (r uintptr) {
|
|
var x uintptr
|
|
_ = x
|
|
_ = NotUsed
|
|
x = __ccgo_fp(libc.Xdlsym)
|
|
return (*(*func(*libc.TLS, uintptr, uintptr) uintptr)(unsafe.Pointer(&struct{ uintptr }{x})))(tls, p, zSym)
|
|
}
|
|
|
|
func _unixEnterMutex(tls *libc.TLS) {
|
|
/* Not a recursive mutex */
|
|
Xsqlite3_mutex_enter(tls, _unixBigLock)
|
|
}
|
|
|
|
var _unixEpoch = libc.Int64FromInt32(24405875) * libc.Int64FromInt32(8640000)
|
|
|
|
func _unixLeaveMutex(tls *libc.TLS) {
|
|
Xsqlite3_mutex_leave(tls, _unixBigLock)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the sector size in bytes of the underlying block device for
|
|
// ** the specified file. This is almost always 512 bytes, but may be
|
|
// ** larger for some devices.
|
|
// **
|
|
// ** SQLite code assumes this function cannot fail. It also assumes that
|
|
// ** if two files are created in the same file-system directory (i.e.
|
|
// ** a database and its journal file) that the sector size will be the
|
|
// ** same for both.
|
|
// */
|
|
func _unixSectorSize(tls *libc.TLS, id uintptr) (r int32) {
|
|
var pFd uintptr
|
|
_ = pFd
|
|
pFd = id
|
|
_setDeviceCharacteristics(tls, pFd)
|
|
return (*TunixFile)(unsafe.Pointer(pFd)).FsectorSize
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the minimum number of 32KB shm regions that should be mapped at
|
|
// ** a time, assuming that each mapping must be an integer multiple of the
|
|
// ** current system page-size.
|
|
// **
|
|
// ** Usually, this is 1. The exception seems to be systems that are configured
|
|
// ** to use 64KB pages - in this case each mapping must cover at least two
|
|
// ** shm regions.
|
|
// */
|
|
func _unixShmRegionPerMap(tls *libc.TLS) (r int32) {
|
|
var pgsz, shmsz int32
|
|
_, _ = pgsz, shmsz
|
|
shmsz = libc.Int32FromInt32(32) * libc.Int32FromInt32(1024) /* SHM region size */
|
|
pgsz = (*(*func(*libc.TLS) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(25)].FpCurrent})))(tls) /* System page size */
|
|
/* Page size must be a power of 2 */
|
|
if pgsz < shmsz {
|
|
return int32(1)
|
|
}
|
|
return pgsz / shmsz
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
|
|
// ** must be either NO_LOCK or SHARED_LOCK.
|
|
// **
|
|
// ** If the locking level of the file descriptor is already at or below
|
|
// ** the requested locking level, this routine is a no-op.
|
|
// */
|
|
func _unixUnlock(tls *libc.TLS, id uintptr, eFileLock int32) (r int32) {
|
|
return _posixUnlock(tls, id, eFileLock, 0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Write data from a buffer into a file. Return SQLITE_OK on success
|
|
// ** or some other error code on failure.
|
|
// */
|
|
func _unixWrite(tls *libc.TLS, id uintptr, pBuf uintptr, amt int32, offset Tsqlite3_int64) (r int32) {
|
|
var pFile uintptr
|
|
var wrote, v1 int32
|
|
_, _, _ = pFile, wrote, v1
|
|
pFile = id
|
|
wrote = 0
|
|
/* If this is a database file (not a journal, super-journal or temp
|
|
** file), the bytes in the locking range should never be read or written. */
|
|
for {
|
|
v1 = _seekAndWrite(tls, pFile, offset, pBuf, amt)
|
|
wrote = v1
|
|
if !(v1 < amt && wrote > 0) {
|
|
break
|
|
}
|
|
amt = amt - wrote
|
|
offset = offset + int64(wrote)
|
|
pBuf = pBuf + uintptr(wrote)
|
|
}
|
|
if amt > wrote {
|
|
if wrote < 0 && (*TunixFile)(unsafe.Pointer(pFile)).FlastErrno != int32(ENOSPC) {
|
|
/* lastErrno set by seekAndWrite */
|
|
return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(3)<<libc.Int32FromInt32(8)
|
|
} else {
|
|
_storeLastErrno(tls, pFile, 0) /* not a system error */
|
|
return int32(SQLITE_FULL)
|
|
}
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
/*
|
|
** We do not trust systems to provide a working fdatasync(). Some do.
|
|
** Others do no. To be safe, we will stick with the (slightly slower)
|
|
** fsync(). If you know that your system does support fdatasync() correctly,
|
|
** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC
|
|
*/
|
|
|
|
/*
|
|
** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
|
|
** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently
|
|
** only available on Mac OS X. But that could change.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If there are no outstanding cursors and we are not in the middle
|
|
// ** of a transaction but there is a read lock on the database, then
|
|
// ** this routine unrefs the first page of the database file which
|
|
// ** has the effect of releasing the read lock.
|
|
// **
|
|
// ** If there is a transaction in progress, this routine is a no-op.
|
|
// */
|
|
func _unlockBtreeIfUnused(tls *libc.TLS, pBt uintptr) {
|
|
var pPage1 uintptr
|
|
_ = pPage1
|
|
if libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FinTransaction) == TRANS_NONE && (*TBtShared)(unsafe.Pointer(pBt)).FpPage1 != uintptr(0) {
|
|
pPage1 = (*TBtShared)(unsafe.Pointer(pBt)).FpPage1
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FpPage1 = uintptr(0)
|
|
_releasePageOne(tls, pPage1)
|
|
}
|
|
}
|
|
|
|
func _vdbeCompareMemString(tls *libc.TLS, pMem1 uintptr, pMem2 uintptr, pColl uintptr, prcErr uintptr) (r int32) {
|
|
if libc.Int32FromUint8((*TMem)(unsafe.Pointer(pMem1)).Fenc) == libc.Int32FromUint8((*TCollSeq)(unsafe.Pointer(pColl)).Fenc) {
|
|
/* The strings are already in the correct encoding. Call the
|
|
** comparison function directly */
|
|
return (*(*func(*libc.TLS, uintptr, int32, uintptr, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{(*TCollSeq)(unsafe.Pointer(pColl)).FxCmp})))(tls, (*TCollSeq)(unsafe.Pointer(pColl)).FpUser, (*TMem)(unsafe.Pointer(pMem1)).Fn, (*TMem)(unsafe.Pointer(pMem1)).Fz, (*TMem)(unsafe.Pointer(pMem2)).Fn, (*TMem)(unsafe.Pointer(pMem2)).Fz)
|
|
} else {
|
|
return _vdbeCompareMemStringWithEncodingChange(tls, pMem1, pMem2, pColl, prcErr)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Release memory held by the Mem p, both external memory cleared
|
|
// ** by p->xDel and memory in p->zMalloc.
|
|
// **
|
|
// ** This is a helper routine invoked by sqlite3VdbeMemRelease() in
|
|
// ** the unusual case where there really is memory in p that needs
|
|
// ** to be freed.
|
|
// */
|
|
func _vdbeMemClear(tls *libc.TLS, p uintptr) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_Agg)|libc.Int32FromInt32(MEM_Dyn)) != 0 {
|
|
_vdbeMemClearExternAndSetNull(tls, p)
|
|
}
|
|
if (*TMem)(unsafe.Pointer(p)).FszMalloc != 0 {
|
|
_sqlite3DbFreeNN(tls, (*TMem)(unsafe.Pointer(p)).Fdb, (*TMem)(unsafe.Pointer(p)).FzMalloc)
|
|
(*TMem)(unsafe.Pointer(p)).FszMalloc = 0
|
|
}
|
|
(*TMem)(unsafe.Pointer(p)).Fz = uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read a varint from the stream of data accessed by p. Set *pnOut to
|
|
// ** the value read.
|
|
// */
|
|
func _vdbePmaReadVarint(tls *libc.TLS, p uintptr, pnOut uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var i, iBuf, rc, v1 int32
|
|
var _ /* a at bp+16 */ uintptr
|
|
var _ /* aVarint at bp+0 */ [16]Tu8
|
|
_, _, _, _ = i, iBuf, rc, v1
|
|
if (*TPmaReader)(unsafe.Pointer(p)).FaMap != 0 {
|
|
**(**Ti64)(__ccgo_up(p)) += libc.Int64FromUint8(_sqlite3GetVarint(tls, (*TPmaReader)(unsafe.Pointer(p)).FaMap+uintptr((*TPmaReader)(unsafe.Pointer(p)).FiReadOff), pnOut))
|
|
} else {
|
|
iBuf = int32((*TPmaReader)(unsafe.Pointer(p)).FiReadOff % int64((*TPmaReader)(unsafe.Pointer(p)).FnBuffer))
|
|
if iBuf != 0 && (*TPmaReader)(unsafe.Pointer(p)).FnBuffer-iBuf >= int32(9) {
|
|
**(**Ti64)(__ccgo_up(p)) += libc.Int64FromUint8(_sqlite3GetVarint(tls, (*TPmaReader)(unsafe.Pointer(p)).FaBuffer+uintptr(iBuf), pnOut))
|
|
} else {
|
|
i = 0
|
|
for cond := true; cond; cond = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 16)))))&int32(0x80) != 0 {
|
|
rc = _vdbePmaReadBlob(tls, p, int32(1), bp+16)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
v1 = i
|
|
i = i + 1
|
|
(**(**[16]Tu8)(__ccgo_up(bp)))[v1&int32(0xf)] = **(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 16))))
|
|
}
|
|
_sqlite3GetVarint(tls, bp, pnOut)
|
|
}
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize PmaReader pReadr to scan through the PMA stored in file pFile
|
|
// ** starting at offset iStart and ending at offset iEof-1. This function
|
|
// ** leaves the PmaReader pointing to the first key in the PMA (or EOF if the
|
|
// ** PMA is empty).
|
|
// **
|
|
// ** If the pnByte parameter is NULL, then it is assumed that the file
|
|
// ** contains a single PMA, and that that PMA omits the initial length varint.
|
|
// */
|
|
func _vdbePmaReaderInit(tls *libc.TLS, pTask uintptr, pFile uintptr, iStart Ti64, pReadr uintptr, pnByte uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc int32
|
|
var v1 uintptr
|
|
var _ /* nByte at bp+0 */ Tu64
|
|
_, _ = rc, v1
|
|
rc = _vdbePmaReaderSeek(tls, pTask, pReadr, pFile, iStart)
|
|
if rc == SQLITE_OK {
|
|
**(**Tu64)(__ccgo_up(bp)) = uint64(0) /* Size of PMA in bytes */
|
|
rc = _vdbePmaReadVarint(tls, pReadr, bp)
|
|
(*TPmaReader)(unsafe.Pointer(pReadr)).FiEof = libc.Int64FromUint64(libc.Uint64FromInt64((*TPmaReader)(unsafe.Pointer(pReadr)).FiReadOff) + **(**Tu64)(__ccgo_up(bp)))
|
|
v1 = pnByte
|
|
*(*Ti64)(unsafe.Pointer(v1)) = Ti64(uint64(*(*Ti64)(unsafe.Pointer(v1))) + **(**Tu64)(__ccgo_up(bp)))
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _vdbePmaReaderNext(tls, pReadr)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The first argument passed to this function is a serial-type that
|
|
// ** corresponds to an integer - all values between 1 and 9 inclusive
|
|
// ** except 7. The second points to a buffer containing an integer value
|
|
// ** serialized according to serial_type. This function deserializes
|
|
// ** and returns the value.
|
|
// */
|
|
func _vdbeRecordDecodeInt(tls *libc.TLS, serial_type Tu32, aKey uintptr) (r Ti64) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var _ /* x at bp+8 */ Tu64
|
|
var _ /* y at bp+0 */ Tu32
|
|
switch serial_type {
|
|
case uint32(0):
|
|
fallthrough
|
|
case uint32(1):
|
|
return int64(libc.Int8FromUint8(**(**Tu8)(__ccgo_up(aKey))))
|
|
case uint32(2):
|
|
return int64(libc.Int32FromInt32(256)*int32(libc.Int8FromUint8(**(**Tu8)(__ccgo_up(aKey)))) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 1))))
|
|
case uint32(3):
|
|
return 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 uint32(4):
|
|
**(**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)))
|
|
return int64(**(**int32)(__ccgo_up(bp)))
|
|
case uint32(5):
|
|
return 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 uint32(6):
|
|
**(**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))))
|
|
return **(**Ti64)(__ccgo_up(bp + 8))
|
|
}
|
|
return libc.Int64FromUint32(serial_type - libc.Uint32FromInt32(8))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** A specially optimized version of vdbeSorterCompare() that assumes that
|
|
// ** the first field of each key is an INTEGER value.
|
|
// */
|
|
func _vdbeSorterCompareInt(tls *libc.TLS, pTask uintptr, pbKey2Cached uintptr, pKey1 uintptr, nKey1 int32, pKey2 uintptr, nKey2 int32) (r int32) {
|
|
var i, res, s1, s2, v21, v3 int32
|
|
var n Tu8
|
|
var p1, p2, v1, v2 uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = i, n, p1, p2, res, s1, s2, v1, v2, v21, v3
|
|
p1 = pKey1
|
|
p2 = pKey2
|
|
s1 = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(p1 + 1))) /* Left hand serial type */
|
|
s2 = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(p2 + 1))) /* Right hand serial type */
|
|
v1 = p1 + uintptr(**(**Tu8)(__ccgo_up(p1))) /* Pointer to value 1 */
|
|
v2 = p2 + uintptr(**(**Tu8)(__ccgo_up(p2))) /* Return value */
|
|
if s1 == s2 {
|
|
n = _aLen[s1]
|
|
res = 0
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint8(n)) {
|
|
break
|
|
}
|
|
v21 = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1 + uintptr(i)))) - libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v2 + uintptr(i))))
|
|
res = v21
|
|
if v21 != 0 {
|
|
if (libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))^libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v2))))&int32(0x80) != 0 {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&int32(0x80) != 0 {
|
|
v3 = -int32(1)
|
|
} else {
|
|
v3 = +libc.Int32FromInt32(1)
|
|
}
|
|
res = v3
|
|
}
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
} else {
|
|
if s1 > int32(7) && s2 > int32(7) {
|
|
res = s1 - s2
|
|
} else {
|
|
if s2 > int32(7) {
|
|
res = +libc.Int32FromInt32(1)
|
|
} else {
|
|
if s1 > int32(7) {
|
|
res = -int32(1)
|
|
} else {
|
|
res = s1 - s2
|
|
}
|
|
}
|
|
if res > 0 {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&int32(0x80) != 0 {
|
|
res = -int32(1)
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v2)))&int32(0x80) != 0 {
|
|
res = +libc.Int32FromInt32(1)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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
|
|
//
|
|
// /*
|
|
// ** Return the SorterCompare function to compare values collected by the
|
|
// ** sorter object passed as the only argument.
|
|
// */
|
|
func _vdbeSorterGetCompare(tls *libc.TLS, p uintptr) (r TSorterCompare) {
|
|
if libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(p)).FtypeMask) == int32(SORTER_TYPE_INTEGER) {
|
|
return __ccgo_fp(_vdbeSorterCompareInt)
|
|
} else {
|
|
if libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(p)).FtypeMask) == int32(SORTER_TYPE_TEXT) {
|
|
return __ccgo_fp(_vdbeSorterCompareText)
|
|
}
|
|
}
|
|
return __ccgo_fp(_vdbeSorterCompare)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute a hash on a page number. The resulting hash value must land
|
|
// ** between 0 and (HASHTABLE_NSLOT-1). The walNextHash() function advances
|
|
// ** the hash to the next value in the event of a collision.
|
|
// */
|
|
func _walHash(tls *libc.TLS, iPage Tu32) (r int32) {
|
|
return libc.Int32FromUint32(iPage * uint32(HASHTABLE_HASH_1) & libc.Uint32FromInt32(libc.Int32FromInt32(HASHTABLE_NPAGE)*libc.Int32FromInt32(2)-libc.Int32FromInt32(1)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read the wal-index header from the wal-index and into pWal->hdr.
|
|
// ** If the wal-header appears to be corrupt, try to reconstruct the
|
|
// ** wal-index from the WAL before returning.
|
|
// **
|
|
// ** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
|
|
// ** changed by this operation. If pWal->hdr is unchanged, set *pChanged
|
|
// ** to 0.
|
|
// **
|
|
// ** If the wal-index header is successfully read, return SQLITE_OK.
|
|
// ** Otherwise an SQLite error code.
|
|
// */
|
|
func _walIndexReadHdr(tls *libc.TLS, pWal uintptr, pChanged uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var bWriteLock, badHdr, rc, v1 int32
|
|
var v4 bool
|
|
var _ /* page0 at bp+0 */ uintptr
|
|
_, _, _, _, _ = bWriteLock, badHdr, rc, v1, v4 /* Chunk of wal-index containing header */
|
|
/* Ensure that page 0 of the wal-index (the page that contains the
|
|
** wal-index header) is mapped. Return early if an error occurs here.
|
|
*/
|
|
rc = _walIndexPage(tls, pWal, 0, bp)
|
|
if rc != SQLITE_OK {
|
|
/* READONLY changed to OK in walIndexPage */
|
|
if rc == libc.Int32FromInt32(SQLITE_READONLY)|libc.Int32FromInt32(5)<<libc.Int32FromInt32(8) {
|
|
/* The SQLITE_READONLY_CANTINIT return means that the shared-memory
|
|
** was openable but is not writable, and this thread is unable to
|
|
** confirm that another write-capable connection has the shared-memory
|
|
** open, and hence the content of the shared-memory is unreliable,
|
|
** since the shared-memory might be inconsistent with the WAL file
|
|
** and there is no writer on hand to fix it. */
|
|
(*TWal)(unsafe.Pointer(pWal)).FbShmUnreliable = uint8(1)
|
|
(*TWal)(unsafe.Pointer(pWal)).FexclusiveMode = uint8(WAL_HEAPMEMORY_MODE)
|
|
**(**int32)(__ccgo_up(pChanged)) = int32(1)
|
|
} else {
|
|
return rc /* Any other non-OK return is just an error */
|
|
}
|
|
} else {
|
|
/* page0 can be NULL if the SHM is zero bytes in size and pWal->writeLock
|
|
** is zero, which prevents the SHM from growing */
|
|
}
|
|
/* If the first page of the wal-index has been mapped, try to read the
|
|
** wal-index header immediately, without holding any lock. This usually
|
|
** works, but may fail if the wal-index header is corrupt or currently
|
|
** being modified by another thread or process.
|
|
*/
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
v1 = _walIndexTryHdr(tls, pWal, pChanged)
|
|
} else {
|
|
v1 = int32(1)
|
|
}
|
|
badHdr = v1
|
|
/* If the first attempt failed, it might have been due to a race
|
|
** with a writer. So get a WRITE lock and try again.
|
|
*/
|
|
if badHdr != 0 {
|
|
if libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FbShmUnreliable) == 0 && libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FreadOnly)&int32(WAL_SHM_RDONLY) != 0 {
|
|
v1 = _walLockShared(tls, pWal, WAL_WRITE_LOCK)
|
|
rc = v1
|
|
if SQLITE_OK == v1 {
|
|
_walUnlockShared(tls, pWal, WAL_WRITE_LOCK)
|
|
rc = libc.Int32FromInt32(SQLITE_READONLY) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
}
|
|
} else {
|
|
bWriteLock = libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FwriteLock)
|
|
if v4 = bWriteLock != 0; !v4 {
|
|
v1 = _walLockExclusive(tls, pWal, WAL_WRITE_LOCK, int32(1))
|
|
rc = v1
|
|
}
|
|
if v4 || SQLITE_OK == v1 {
|
|
/* If the write-lock was just obtained, set writeLock to 2 instead of
|
|
** the usual 1. This causes walIndexPage() to behave as if the
|
|
** write-lock were held (so that it allocates new pages as required),
|
|
** and walHandleException() to unlock the write-lock if a SEH exception
|
|
** is thrown. */
|
|
if !(bWriteLock != 0) {
|
|
(*TWal)(unsafe.Pointer(pWal)).FwriteLock = uint8(2)
|
|
}
|
|
v1 = _walIndexPage(tls, pWal, 0, bp)
|
|
rc = v1
|
|
if SQLITE_OK == v1 {
|
|
badHdr = _walIndexTryHdr(tls, pWal, pChanged)
|
|
if badHdr != 0 {
|
|
/* If the wal-index header is still malformed even while holding
|
|
** a WRITE lock, it can only mean that the header is corrupted and
|
|
** needs to be reconstructed. So run recovery to do exactly that.
|
|
** Disable blocking locks first. */
|
|
rc = _walIndexRecover(tls, pWal)
|
|
**(**int32)(__ccgo_up(pChanged)) = int32(1)
|
|
}
|
|
}
|
|
if bWriteLock == 0 {
|
|
(*TWal)(unsafe.Pointer(pWal)).FwriteLock = uint8(0)
|
|
_walUnlockExclusive(tls, pWal, WAL_WRITE_LOCK, int32(1))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* If the header is read successfully, check the version number to make
|
|
** sure the wal-index was not constructed with some future format that
|
|
** this version of SQLite cannot understand.
|
|
*/
|
|
if badHdr == 0 && (*TWal)(unsafe.Pointer(pWal)).Fhdr.FiVersion != uint32(WALINDEX_MAX_VERSION) {
|
|
rc = _sqlite3CantopenError(tls, int32(70266))
|
|
}
|
|
if (*TWal)(unsafe.Pointer(pWal)).FbShmUnreliable != 0 {
|
|
if rc != SQLITE_OK {
|
|
_walIndexClose(tls, pWal, 0)
|
|
(*TWal)(unsafe.Pointer(pWal)).FbShmUnreliable = uint8(0)
|
|
/* walIndexRecover() might have returned SHORT_READ if a concurrent
|
|
** writer truncated the WAL out from under it. If that happens, it
|
|
** indicates that a writer has fixed the SHM file for us, so retry */
|
|
if rc == libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(2)<<libc.Int32FromInt32(8) {
|
|
rc = -int32(1)
|
|
}
|
|
}
|
|
(*TWal)(unsafe.Pointer(pWal)).FexclusiveMode = uint8(WAL_NORMAL_MODE)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The cache of the wal-index header must be valid to call this function.
|
|
// ** Return the page-size in bytes used by the database.
|
|
// */
|
|
func _walPagesize(tls *libc.TLS, pWal uintptr) (r int32) {
|
|
return libc.Int32FromUint16((*TWal)(unsafe.Pointer(pWal)).Fhdr.FszPage)&int32(0xfe00) + libc.Int32FromUint16((*TWal)(unsafe.Pointer(pWal)).Fhdr.FszPage)&int32(0x0001)<<int32(16)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If there is the possibility of concurrent access to the SHM file
|
|
// ** from multiple threads and/or processes, then do a memory barrier.
|
|
// */
|
|
func _walShmBarrier(tls *libc.TLS, pWal uintptr) {
|
|
if libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FexclusiveMode) != int32(WAL_HEAPMEMORY_MODE) {
|
|
_sqlite3OsShmBarrier(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd)
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Add the SQLITE_NO_TSAN as part of the return-type of a function
|
|
** definition as a hint that the function contains constructs that
|
|
** might give false-positive TSAN warnings.
|
|
**
|
|
** See tag-20200519-1.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Subterms pOne and pTwo are contained within WHERE clause pWC. The
|
|
// ** two subterms are in disjunction - they are OR-ed together.
|
|
// **
|
|
// ** If these two terms are both of the form: "A op B" with the same
|
|
// ** A and B values but different operators and if the operators are
|
|
// ** compatible (if one is = and the other is <, for example) then
|
|
// ** add a new virtual AND term to pWC that is the combination of the
|
|
// ** two.
|
|
// **
|
|
// ** Some examples:
|
|
// **
|
|
// ** x<y OR x=y --> x<=y
|
|
// ** x=y OR x=y --> x=y
|
|
// ** x<=y OR x<y --> x<=y
|
|
// **
|
|
// ** The following is NOT generated:
|
|
// **
|
|
// ** x<y OR x>y --> x!=y
|
|
// */
|
|
func _whereCombineDisjuncts(tls *libc.TLS, pSrc uintptr, pWC uintptr, pOne uintptr, pTwo uintptr) {
|
|
var db, pA, pB, pNew uintptr
|
|
var eOp Tu16
|
|
var idxNew, op int32
|
|
_, _, _, _, _, _, _ = db, eOp, idxNew, op, pA, pB, pNew
|
|
eOp = libc.Uint16FromInt32(libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pOne)).FeOperator) | libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTwo)).FeOperator)) /* Expressions associated with pOne and pTwo */
|
|
if (libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pOne)).FwtFlags)|libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTwo)).FwtFlags))&int32(TERM_VNULL) != 0 {
|
|
return
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pOne)).FeOperator)&(libc.Int32FromInt32(WO_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_EQ)<<(libc.Int32FromInt32(TK_GT)-libc.Int32FromInt32(TK_EQ))|libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_GE)-libc.Int32FromInt32(TK_EQ))) == 0 {
|
|
return
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTwo)).FeOperator)&(libc.Int32FromInt32(WO_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_EQ)<<(libc.Int32FromInt32(TK_GT)-libc.Int32FromInt32(TK_EQ))|libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_GE)-libc.Int32FromInt32(TK_EQ))) == 0 {
|
|
return
|
|
}
|
|
if libc.Int32FromUint16(eOp)&(libc.Int32FromInt32(WO_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.Int32FromUint16(eOp) && libc.Int32FromUint16(eOp)&(libc.Int32FromInt32(WO_EQ)|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.Int32FromUint16(eOp) {
|
|
return
|
|
}
|
|
pA = (*TWhereTerm)(unsafe.Pointer(pOne)).FpExpr
|
|
pB = (*TWhereTerm)(unsafe.Pointer(pTwo)).FpExpr
|
|
if _sqlite3ExprCompare(tls, uintptr(0), (*TExpr)(unsafe.Pointer(pA)).FpLeft, (*TExpr)(unsafe.Pointer(pB)).FpLeft, -int32(1)) != 0 {
|
|
return
|
|
}
|
|
if _sqlite3ExprCompare(tls, uintptr(0), (*TExpr)(unsafe.Pointer(pA)).FpRight, (*TExpr)(unsafe.Pointer(pB)).FpRight, -int32(1)) != 0 {
|
|
return
|
|
}
|
|
if libc.BoolInt32((*TExpr)(unsafe.Pointer(pA)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Commuted)) != uint32(0)) != libc.BoolInt32((*TExpr)(unsafe.Pointer(pB)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Commuted)) != uint32(0)) {
|
|
return
|
|
}
|
|
/* If we reach this point, it means the two subterms can be combined */
|
|
if libc.Int32FromUint16(eOp)&(libc.Int32FromUint16(eOp)-int32(1)) != 0 {
|
|
if libc.Int32FromUint16(eOp)&(libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LT)-libc.Int32FromInt32(TK_EQ))|libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LE)-libc.Int32FromInt32(TK_EQ))) != 0 {
|
|
eOp = libc.Uint16FromInt32(libc.Int32FromInt32(WO_EQ) << (libc.Int32FromInt32(TK_LE) - libc.Int32FromInt32(TK_EQ)))
|
|
} else {
|
|
eOp = libc.Uint16FromInt32(libc.Int32FromInt32(WO_EQ) << (libc.Int32FromInt32(TK_GE) - libc.Int32FromInt32(TK_EQ)))
|
|
}
|
|
}
|
|
db = (*TParse)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer((*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo)).FpParse)).Fdb
|
|
pNew = _sqlite3ExprDup(tls, db, pA, 0)
|
|
if pNew == uintptr(0) {
|
|
return
|
|
}
|
|
op = int32(TK_EQ)
|
|
for {
|
|
if !(libc.Int32FromUint16(eOp) != int32(WO_EQ)<<(op-int32(TK_EQ))) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
op = op + 1
|
|
}
|
|
(*TExpr)(unsafe.Pointer(pNew)).Fop = libc.Uint8FromInt32(op)
|
|
idxNew = _whereClauseInsert(tls, pWC, pNew, libc.Uint16FromInt32(libc.Int32FromInt32(TERM_VIRTUAL)|libc.Int32FromInt32(TERM_DYNAMIC)))
|
|
_exprAnalyze(tls, pSrc, pWC, idxNew)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Try to adjust the cost and number of output rows of WhereLoop pTemplate
|
|
// ** upwards or downwards so that:
|
|
// **
|
|
// ** (1) pTemplate costs less than any other WhereLoops that are a proper
|
|
// ** subset of pTemplate
|
|
// **
|
|
// ** (2) pTemplate costs more than any other WhereLoops for which pTemplate
|
|
// ** is a proper subset.
|
|
// **
|
|
// ** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
|
|
// ** WHERE clause terms than Y and that every WHERE clause term used by X is
|
|
// ** also used by Y.
|
|
// */
|
|
func _whereLoopAdjustCost(tls *libc.TLS, p uintptr, pTemplate uintptr) {
|
|
var v2 int32
|
|
_ = v2
|
|
if (*TWhereLoop)(unsafe.Pointer(pTemplate)).FwsFlags&uint32(WHERE_INDEXED) == uint32(0) {
|
|
return
|
|
}
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(p)).FiTab) != libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(pTemplate)).FiTab) {
|
|
goto _1
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).FwsFlags&uint32(WHERE_INDEXED) == uint32(0) {
|
|
goto _1
|
|
}
|
|
if _whereLoopCheaperProperSubset(tls, p, pTemplate) != 0 {
|
|
/* Adjust pTemplate cost downward so that it is cheaper than its
|
|
** subset p. */
|
|
if int32((*TWhereLoop)(unsafe.Pointer(p)).FrRun) < int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FrRun) {
|
|
v2 = int32((*TWhereLoop)(unsafe.Pointer(p)).FrRun)
|
|
} else {
|
|
v2 = int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FrRun)
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pTemplate)).FrRun = int16(v2)
|
|
if int32((*TWhereLoop)(unsafe.Pointer(p)).FnOut)-int32(1) < int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FnOut) {
|
|
v2 = int32((*TWhereLoop)(unsafe.Pointer(p)).FnOut) - int32(1)
|
|
} else {
|
|
v2 = int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FnOut)
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pTemplate)).FnOut = int16(v2)
|
|
} else {
|
|
if _whereLoopCheaperProperSubset(tls, pTemplate, p) != 0 {
|
|
/* Adjust pTemplate cost upward so that it is costlier than p since
|
|
** pTemplate is a proper subset of p */
|
|
if int32((*TWhereLoop)(unsafe.Pointer(p)).FrRun) > int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FrRun) {
|
|
v2 = int32((*TWhereLoop)(unsafe.Pointer(p)).FrRun)
|
|
} else {
|
|
v2 = int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FrRun)
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pTemplate)).FrRun = int16(v2)
|
|
if int32((*TWhereLoop)(unsafe.Pointer(p)).FnOut)+int32(1) > int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FnOut) {
|
|
v2 = int32((*TWhereLoop)(unsafe.Pointer(p)).FnOut) + int32(1)
|
|
} else {
|
|
v2 = int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FnOut)
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pTemplate)).FnOut = int16(v2)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TWhereLoop)(unsafe.Pointer(p)).FpNextLoop
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact.
|
|
// */
|
|
func _whereLoopClearUnion(tls *libc.TLS, db uintptr, p uintptr) {
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).FwsFlags&libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_VIRTUALTABLE)|libc.Int32FromInt32(WHERE_AUTO_INDEX)) != 0 {
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).FwsFlags&uint32(WHERE_VIRTUALTABLE) != uint32(0) && int32(Tu32(*(*uint8)(unsafe.Pointer(p + 24 + 4))&0x1>>0)) != 0 {
|
|
Xsqlite3_free(tls, (*(*struct {
|
|
FidxNum int32
|
|
F__ccgo4 uint8
|
|
FisOrdered Ti8
|
|
FomitMask Tu16
|
|
FidxStr uintptr
|
|
FmHandleIn Tu32
|
|
})(unsafe.Pointer(p + 24))).FidxStr)
|
|
libc.SetBitFieldPtr8Uint32(p+24+4, libc.Uint32FromInt32(0), 0, 0x1)
|
|
(*(*struct {
|
|
FidxNum int32
|
|
F__ccgo4 uint8
|
|
FisOrdered Ti8
|
|
FomitMask Tu16
|
|
FidxStr uintptr
|
|
FmHandleIn Tu32
|
|
})(unsafe.Pointer(p + 24))).FidxStr = uintptr(0)
|
|
} else {
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).FwsFlags&uint32(WHERE_AUTO_INDEX) != uint32(0) && (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(p + 24))).FpIndex != uintptr(0) {
|
|
_sqlite3DbFree(tls, db, (*TIndex)(unsafe.Pointer((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(p + 24))).FpIndex)).FzColAff)
|
|
_sqlite3DbFreeNN(tls, db, (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(p + 24))).FpIndex)
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(p + 24))).FpIndex = uintptr(0)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If it is not NULL, pTerm is a term that provides an upper or lower
|
|
// ** bound on a range scan. Without considering pTerm, it is estimated
|
|
// ** that the scan will visit nNew rows. This function returns the number
|
|
// ** estimated to be visited after taking pTerm into account.
|
|
// **
|
|
// ** If the user explicitly specified a likelihood() value for this term,
|
|
// ** then the return value is the likelihood multiplied by the number of
|
|
// ** input rows. Otherwise, this function assumes that an "IS NOT NULL" term
|
|
// ** has a likelihood of 0.50, and any other term a likelihood of 0.25.
|
|
// */
|
|
func _whereRangeAdjust(tls *libc.TLS, pTerm uintptr, nNew TLogEst) (r TLogEst) {
|
|
var nRet TLogEst
|
|
_ = nRet
|
|
nRet = nNew
|
|
if pTerm != 0 {
|
|
if int32((*TWhereTerm)(unsafe.Pointer(pTerm)).FtruthProb) <= 0 {
|
|
nRet = int16(int32(nRet) + int32((*TWhereTerm)(unsafe.Pointer(pTerm)).FtruthProb))
|
|
} else {
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_VNULL) == 0 {
|
|
nRet = int16(int32(nRet) - libc.Int32FromInt32(20))
|
|
}
|
|
}
|
|
}
|
|
return nRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the right-hand branch of the expression is a TK_COLUMN, then return
|
|
// ** a pointer to the right-hand branch. Otherwise, return NULL.
|
|
// */
|
|
func _whereRightSubexprIsColumn(tls *libc.TLS, p uintptr) (r uintptr) {
|
|
p = _sqlite3ExprSkipCollateAndLikely(tls, (*TExpr)(unsafe.Pointer(p)).FpRight)
|
|
if p != uintptr(0) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_COLUMN) && !((*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_FixedCol)) != libc.Uint32FromInt32(0)) {
|
|
return p
|
|
}
|
|
return uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the cost of sorting nRow rows, assuming that the keys have
|
|
// ** nOrderby columns and that the first nSorted columns are already in
|
|
// ** order.
|
|
// */
|
|
func _whereSortingCost(tls *libc.TLS, pWInfo uintptr, nRow TLogEst, nOrderBy int32, nSorted int32) (r TLogEst) {
|
|
var nCol, rSortCost TLogEst
|
|
_, _ = nCol, rSortCost
|
|
/* TUNING: sorting cost proportional to the number of output columns: */
|
|
nCol = _sqlite3LogEst(tls, libc.Uint64FromInt32(((*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer(pWInfo)).FpSelect)).FpEList)).FnExpr+int32(59))/int32(30)))
|
|
rSortCost = int16(int32(nRow) + int32(nCol))
|
|
if nSorted > 0 {
|
|
/* Scale the result by (Y/X) */
|
|
rSortCost = int16(int32(rSortCost) + (int32(_sqlite3LogEst(tls, libc.Uint64FromInt32((nOrderBy-nSorted)*int32(100)/nOrderBy))) - libc.Int32FromInt32(66)))
|
|
}
|
|
/* Multiple by log(M) where M is the number of output rows.
|
|
** Use the LIMIT for M if it is smaller. Or if this sort is for
|
|
** a DISTINCT operator, M will be the number of distinct output
|
|
** rows, so fudge it downwards a bit.
|
|
*/
|
|
if libc.Int32FromUint16((*TWhereInfo)(unsafe.Pointer(pWInfo)).FwctrlFlags)&int32(WHERE_USE_LIMIT) != 0 {
|
|
rSortCost = int16(int32(rSortCost) + libc.Int32FromInt32(10)) /* TUNING: Extra 2.0x if using LIMIT */
|
|
if nSorted != 0 {
|
|
rSortCost = int16(int32(rSortCost) + libc.Int32FromInt32(6)) /* TUNING: Extra 1.5x if also using partial sort */
|
|
}
|
|
if int32((*TWhereInfo)(unsafe.Pointer(pWInfo)).FiLimit) < int32(nRow) {
|
|
nRow = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FiLimit
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint16((*TWhereInfo)(unsafe.Pointer(pWInfo)).FwctrlFlags)&int32(WHERE_WANT_DISTINCT) != 0 {
|
|
/* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT
|
|
** reduces the number of output rows by a factor of 2 */
|
|
if int32(nRow) > int32(10) {
|
|
nRow = int16(int32(nRow) - libc.Int32FromInt32(10))
|
|
}
|
|
}
|
|
}
|
|
rSortCost = int16(int32(rSortCost) + int32(_estLog(tls, nRow)))
|
|
return rSortCost
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate VM code to invoke either xValue() (bFin==0) or xFinalize()
|
|
// ** (bFin==1) for each window function in the linked list starting at
|
|
// ** pMWin. Or, for built-in window-functions that do not use the standard
|
|
// ** API, generate the equivalent VM code.
|
|
// */
|
|
func _windowAggFinal(tls *libc.TLS, p uintptr, bFin int32) {
|
|
var nArg int32
|
|
var pMWin, pParse, pWin, v uintptr
|
|
_, _, _, _, _ = nArg, pMWin, pParse, pWin, v
|
|
pParse = (*TWindowCodeArg)(unsafe.Pointer(p)).FpParse
|
|
pMWin = (*TWindowCodeArg)(unsafe.Pointer(p)).FpMWin
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
pWin = pMWin
|
|
for {
|
|
if !(pWin != 0) {
|
|
break
|
|
}
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid == 0 && (*TFuncDef)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pWin)).FpWFunc)).FfuncFlags&uint32(SQLITE_FUNC_MINMAX) != 0 && libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pWin)).FeStart) != int32(TK_UNBOUNDED) {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Null), 0, (*TWindow)(unsafe.Pointer(pWin)).FregResult)
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_Last), (*TWindow)(unsafe.Pointer(pWin)).FcsrApp)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), (*TWindow)(unsafe.Pointer(pWin)).FcsrApp, 0, (*TWindow)(unsafe.Pointer(pWin)).FregResult)
|
|
_sqlite3VdbeJumpHere(tls, v, _sqlite3VdbeCurrentAddr(tls, v)-int32(2))
|
|
} else {
|
|
if (*TWindow)(unsafe.Pointer(pWin)).FregApp != 0 {
|
|
} else {
|
|
nArg = _windowArgCount(tls, pWin)
|
|
if bFin != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_AggFinal), (*TWindow)(unsafe.Pointer(pWin)).FregAccum, nArg)
|
|
_sqlite3VdbeAppendP4(tls, v, (*TWindow)(unsafe.Pointer(pWin)).FpWFunc, -int32(8))
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Copy), (*TWindow)(unsafe.Pointer(pWin)).FregAccum, (*TWindow)(unsafe.Pointer(pWin)).FregResult)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Null), 0, (*TWindow)(unsafe.Pointer(pWin)).FregAccum)
|
|
} else {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_AggValue), (*TWindow)(unsafe.Pointer(pWin)).FregAccum, nArg, (*TWindow)(unsafe.Pointer(pWin)).FregResult)
|
|
_sqlite3VdbeAppendP4(tls, v, (*TWindow)(unsafe.Pointer(pWin)).FpWFunc, -int32(8))
|
|
}
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pWin = (*TWindow)(unsafe.Pointer(pWin)).FpNextWin
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Helper function for sqlite3WindowCodeStep(). Each call to this function
|
|
// ** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE
|
|
// ** operation. Refer to the header comment for sqlite3WindowCodeStep() for
|
|
// ** details.
|
|
// */
|
|
func _windowCodeOp(tls *libc.TLS, p uintptr, op int32, regCountdown int32, jumpOnEof int32) (r int32) {
|
|
var addrContinue, addrNextRange, bPeer, csr, lblDone, nReg, reg, regRowid1, regRowid2, regTmp, ret, v1, v2 int32
|
|
var pMWin, pParse, v uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addrContinue, addrNextRange, bPeer, csr, lblDone, nReg, pMWin, pParse, reg, regRowid1, regRowid2, regTmp, ret, v, v1, v2
|
|
pParse = (*TWindowCodeArg)(unsafe.Pointer(p)).FpParse
|
|
pMWin = (*TWindowCodeArg)(unsafe.Pointer(p)).FpMWin
|
|
ret = 0
|
|
v = (*TWindowCodeArg)(unsafe.Pointer(p)).FpVdbe
|
|
addrContinue = 0
|
|
bPeer = libc.BoolInt32(libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeFrmType) != int32(TK_ROWS))
|
|
lblDone = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
addrNextRange = 0
|
|
/* Special case - WINDOW_AGGINVERSE is always a no-op if the frame
|
|
** starts with UNBOUNDED PRECEDING. */
|
|
if op == int32(WINDOW_AGGINVERSE) && libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeStart) == int32(TK_UNBOUNDED) {
|
|
return 0
|
|
}
|
|
if regCountdown > 0 {
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeFrmType) == int32(TK_RANGE) {
|
|
addrNextRange = _sqlite3VdbeCurrentAddr(tls, v)
|
|
if op == int32(WINDOW_AGGINVERSE) {
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeStart) == int32(TK_FOLLOWING) {
|
|
_windowCodeRangeTest(tls, p, int32(OP_Le), (*TWindowCodeArg)(unsafe.Pointer(p)).Fcurrent.Fcsr, regCountdown, (*TWindowCodeArg)(unsafe.Pointer(p)).Fstart.Fcsr, lblDone)
|
|
} else {
|
|
_windowCodeRangeTest(tls, p, int32(OP_Ge), (*TWindowCodeArg)(unsafe.Pointer(p)).Fstart.Fcsr, regCountdown, (*TWindowCodeArg)(unsafe.Pointer(p)).Fcurrent.Fcsr, lblDone)
|
|
}
|
|
} else {
|
|
_windowCodeRangeTest(tls, p, int32(OP_Gt), (*TWindowCodeArg)(unsafe.Pointer(p)).Fend.Fcsr, regCountdown, (*TWindowCodeArg)(unsafe.Pointer(p)).Fcurrent.Fcsr, lblDone)
|
|
}
|
|
} else {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_IfPos), regCountdown, lblDone, int32(1))
|
|
}
|
|
}
|
|
if op == int32(WINDOW_RETURN_ROW) && (*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid == 0 {
|
|
_windowAggFinal(tls, p, 0)
|
|
}
|
|
addrContinue = _sqlite3VdbeCurrentAddr(tls, v)
|
|
/* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or
|
|
** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the
|
|
** start cursor does not advance past the end cursor within the
|
|
** temporary table. It otherwise might, if (a>b). Also ensure that,
|
|
** if the input cursor is still finding new rows, that the end
|
|
** cursor does not go past it to EOF. */
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeStart) == libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeEnd) && regCountdown != 0 && libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeFrmType) == int32(TK_RANGE) {
|
|
regRowid1 = _sqlite3GetTempReg(tls, pParse)
|
|
regRowid2 = _sqlite3GetTempReg(tls, pParse)
|
|
if op == int32(WINDOW_AGGINVERSE) {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), (*TWindowCodeArg)(unsafe.Pointer(p)).Fstart.Fcsr, regRowid1)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), (*TWindowCodeArg)(unsafe.Pointer(p)).Fend.Fcsr, regRowid2)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Ge), regRowid2, lblDone, regRowid1)
|
|
} else {
|
|
if (*TWindowCodeArg)(unsafe.Pointer(p)).FregRowid != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), (*TWindowCodeArg)(unsafe.Pointer(p)).Fend.Fcsr, regRowid1)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Ge), (*TWindowCodeArg)(unsafe.Pointer(p)).FregRowid, lblDone, regRowid1)
|
|
}
|
|
}
|
|
_sqlite3ReleaseTempReg(tls, pParse, regRowid1)
|
|
_sqlite3ReleaseTempReg(tls, pParse, regRowid2)
|
|
}
|
|
switch op {
|
|
case int32(WINDOW_RETURN_ROW):
|
|
csr = (*TWindowCodeArg)(unsafe.Pointer(p)).Fcurrent.Fcsr
|
|
reg = (*TWindowCodeArg)(unsafe.Pointer(p)).Fcurrent.Freg
|
|
_windowReturnOneRow(tls, p)
|
|
case int32(WINDOW_AGGINVERSE):
|
|
csr = (*TWindowCodeArg)(unsafe.Pointer(p)).Fstart.Fcsr
|
|
reg = (*TWindowCodeArg)(unsafe.Pointer(p)).Fstart.Freg
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_AddImm), (*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid, int32(1))
|
|
} else {
|
|
_windowAggStep(tls, p, pMWin, csr, int32(1), (*TWindowCodeArg)(unsafe.Pointer(p)).FregArg)
|
|
}
|
|
default:
|
|
csr = (*TWindowCodeArg)(unsafe.Pointer(p)).Fend.Fcsr
|
|
reg = (*TWindowCodeArg)(unsafe.Pointer(p)).Fend.Freg
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_AddImm), (*TWindow)(unsafe.Pointer(pMWin)).FregEndRowid, int32(1))
|
|
} else {
|
|
_windowAggStep(tls, p, pMWin, csr, 0, (*TWindowCodeArg)(unsafe.Pointer(p)).FregArg)
|
|
}
|
|
break
|
|
}
|
|
if op == (*TWindowCodeArg)(unsafe.Pointer(p)).FeDelete {
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_Delete), csr)
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(OPFLAG_SAVEPOSITION))
|
|
}
|
|
if jumpOnEof != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), csr, _sqlite3VdbeCurrentAddr(tls, v)+int32(2))
|
|
ret = _sqlite3VdbeAddOp0(tls, v, int32(OP_Goto))
|
|
} else {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), csr, _sqlite3VdbeCurrentAddr(tls, v)+int32(1)+bPeer)
|
|
if bPeer != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Goto), 0, lblDone)
|
|
}
|
|
}
|
|
if bPeer != 0 {
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy != 0 {
|
|
v1 = (*TExprList)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy)).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
nReg = v1
|
|
if nReg != 0 {
|
|
v2 = _sqlite3GetTempRange(tls, pParse, nReg)
|
|
} else {
|
|
v2 = 0
|
|
}
|
|
regTmp = v2
|
|
_windowReadPeerValues(tls, p, csr, regTmp)
|
|
_windowIfNewPeer(tls, pParse, (*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy, regTmp, reg, addrContinue)
|
|
_sqlite3ReleaseTempRange(tls, pParse, regTmp, nReg)
|
|
}
|
|
if addrNextRange != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Goto), 0, addrNextRange)
|
|
}
|
|
_sqlite3VdbeResolveLabel(tls, v, lblDone)
|
|
return ret
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code to calculate the current values of all window functions in the
|
|
// ** p->pMWin list by doing a full scan of the current window frame. Store the
|
|
// ** results in the Window.regResult registers, ready to return the upper
|
|
// ** layer.
|
|
// */
|
|
func _windowFullScan(tls *libc.TLS, p uintptr) {
|
|
var addr, addrEq, addrNext, csr, lblBrk, lblNext, nPeer, regCPeer, regCRowid, regPeer, regRowid, v1 int32
|
|
var pKeyInfo, pMWin, pParse, pWin, v uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addr, addrEq, addrNext, csr, lblBrk, lblNext, nPeer, pKeyInfo, pMWin, pParse, pWin, regCPeer, regCRowid, regPeer, regRowid, v, v1
|
|
pParse = (*TWindowCodeArg)(unsafe.Pointer(p)).FpParse
|
|
pMWin = (*TWindowCodeArg)(unsafe.Pointer(p)).FpMWin
|
|
v = (*TWindowCodeArg)(unsafe.Pointer(p)).FpVdbe
|
|
regCRowid = 0 /* Current rowid value */
|
|
regCPeer = 0 /* Current peer values */
|
|
regRowid = 0 /* AggStep rowid value */
|
|
regPeer = 0
|
|
csr = (*TWindow)(unsafe.Pointer(pMWin)).FcsrApp
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy != 0 {
|
|
v1 = (*TExprList)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy)).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
nPeer = v1
|
|
lblNext = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
lblBrk = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
regCRowid = _sqlite3GetTempReg(tls, pParse)
|
|
regRowid = _sqlite3GetTempReg(tls, pParse)
|
|
if nPeer != 0 {
|
|
regCPeer = _sqlite3GetTempRange(tls, pParse, nPeer)
|
|
regPeer = _sqlite3GetTempRange(tls, pParse, nPeer)
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr, regCRowid)
|
|
_windowReadPeerValues(tls, p, (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr, regCPeer)
|
|
pWin = pMWin
|
|
for {
|
|
if !(pWin != 0) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Null), 0, (*TWindow)(unsafe.Pointer(pWin)).FregAccum)
|
|
goto _2
|
|
_2:
|
|
;
|
|
pWin = (*TWindow)(unsafe.Pointer(pWin)).FpNextWin
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_SeekGE), csr, lblBrk, (*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid)
|
|
addrNext = _sqlite3VdbeCurrentAddr(tls, v)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), csr, regRowid)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Gt), (*TWindow)(unsafe.Pointer(pMWin)).FregEndRowid, lblBrk, regRowid)
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeExclude) == int32(TK_CURRENT) {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Eq), regCRowid, lblNext, regRowid)
|
|
} else {
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeExclude) != int32(TK_NO) {
|
|
addrEq = 0
|
|
pKeyInfo = uintptr(0)
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy != 0 {
|
|
pKeyInfo = _sqlite3KeyInfoFromExprList(tls, pParse, (*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy, 0, 0)
|
|
}
|
|
if libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pMWin)).FeExclude) == int32(TK_TIES) {
|
|
addrEq = _sqlite3VdbeAddOp3(tls, v, int32(OP_Eq), regCRowid, 0, regRowid)
|
|
}
|
|
if pKeyInfo != 0 {
|
|
_windowReadPeerValues(tls, p, csr, regPeer)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Compare), regPeer, regCPeer, nPeer)
|
|
_sqlite3VdbeAppendP4(tls, v, pKeyInfo, -int32(9))
|
|
addr = _sqlite3VdbeCurrentAddr(tls, v) + int32(1)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Jump), addr, lblNext, addr)
|
|
} else {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Goto), 0, lblNext)
|
|
}
|
|
if addrEq != 0 {
|
|
_sqlite3VdbeJumpHere(tls, v, addrEq)
|
|
}
|
|
}
|
|
}
|
|
_windowAggStep(tls, p, pMWin, csr, 0, (*TWindowCodeArg)(unsafe.Pointer(p)).FregArg)
|
|
_sqlite3VdbeResolveLabel(tls, v, lblNext)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), csr, addrNext)
|
|
_sqlite3VdbeJumpHere(tls, v, addrNext-int32(1))
|
|
_sqlite3VdbeJumpHere(tls, v, addrNext+int32(1))
|
|
_sqlite3ReleaseTempReg(tls, pParse, regRowid)
|
|
_sqlite3ReleaseTempReg(tls, pParse, regCRowid)
|
|
if nPeer != 0 {
|
|
_sqlite3ReleaseTempRange(tls, pParse, regPeer, nPeer)
|
|
_sqlite3ReleaseTempRange(tls, pParse, regCPeer, nPeer)
|
|
}
|
|
_windowAggFinal(tls, p, int32(1))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Functions to serialize a 16 bit integer, 32 bit real number and
|
|
// ** 64 bit integer. The value returned is the number of bytes written
|
|
// ** to the argument buffer (always 2, 4 and 8 respectively).
|
|
// */
|
|
func _writeInt16(tls *libc.TLS, p uintptr, i int32) {
|
|
**(**Tu8)(__ccgo_up(p)) = libc.Uint8FromInt32(i >> int32(8) & int32(0xFF))
|
|
**(**Tu8)(__ccgo_up(p + 1)) = libc.Uint8FromInt32(i >> 0 & int32(0xFF))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* The following function deletes the "minor type" or semantic value
|
|
// ** associated with a symbol. The symbol can be either a terminal
|
|
// ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
|
|
// ** a pointer to the value to be deleted. The code used to do the
|
|
// ** deletions is derived from the %destructor and/or %token_destructor
|
|
// ** directives of the input grammar.
|
|
// */
|
|
func _yy_destructor(tls *libc.TLS, yypParser uintptr, yymajor uint16, yypminor uintptr) {
|
|
var pParse uintptr
|
|
_ = pParse
|
|
pParse = (*TyyParser)(unsafe.Pointer(yypParser)).FpParse
|
|
switch libc.Int32FromUint16(yymajor) {
|
|
/* Here is inserted the actions which take place when a
|
|
** terminal or non-terminal is destroyed. This can happen
|
|
** when the symbol is popped from the stack during a
|
|
** reduce or during error processing or when a parser is
|
|
** being destroyed before it is finished parsing.
|
|
**
|
|
** Note: during a reduce, the only symbols destroyed are those
|
|
** which appear on the RHS of the rule, but which are *not* used
|
|
** inside the C code.
|
|
*/
|
|
/********* Begin destructor definitions ***************************************/
|
|
case int32(206): /* select */
|
|
fallthrough
|
|
case int32(241): /* selectnowith */
|
|
fallthrough
|
|
case int32(242): /* oneselect */
|
|
fallthrough
|
|
case int32(254): /* values */
|
|
fallthrough
|
|
case int32(256): /* mvalues */
|
|
_sqlite3SelectDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(218): /* term */
|
|
fallthrough
|
|
case int32(219): /* expr */
|
|
fallthrough
|
|
case int32(248): /* where_opt */
|
|
fallthrough
|
|
case int32(250): /* having_opt */
|
|
fallthrough
|
|
case int32(270): /* where_opt_ret */
|
|
fallthrough
|
|
case int32(281): /* case_operand */
|
|
fallthrough
|
|
case int32(283): /* case_else */
|
|
fallthrough
|
|
case int32(286): /* vinto */
|
|
fallthrough
|
|
case int32(293): /* when_clause */
|
|
fallthrough
|
|
case int32(297): /* key_opt */
|
|
fallthrough
|
|
case int32(314): /* filter_clause */
|
|
_sqlite3ExprDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(223): /* eidlist_opt */
|
|
fallthrough
|
|
case int32(233): /* sortlist */
|
|
fallthrough
|
|
case int32(234): /* eidlist */
|
|
fallthrough
|
|
case int32(246): /* selcollist */
|
|
fallthrough
|
|
case int32(249): /* groupby_opt */
|
|
fallthrough
|
|
case int32(251): /* orderby_opt */
|
|
fallthrough
|
|
case int32(255): /* nexprlist */
|
|
fallthrough
|
|
case int32(257): /* sclp */
|
|
fallthrough
|
|
case int32(264): /* exprlist */
|
|
fallthrough
|
|
case int32(271): /* setlist */
|
|
fallthrough
|
|
case int32(280): /* paren_exprlist */
|
|
fallthrough
|
|
case int32(282): /* case_exprlist */
|
|
fallthrough
|
|
case int32(313): /* part_opt */
|
|
_sqlite3ExprListDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(240): /* fullname */
|
|
fallthrough
|
|
case int32(247): /* from */
|
|
fallthrough
|
|
case int32(259): /* seltablist */
|
|
fallthrough
|
|
case int32(260): /* stl_prefix */
|
|
fallthrough
|
|
case int32(265): /* xfullname */
|
|
_sqlite3SrcListDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(243): /* wqlist */
|
|
_sqlite3WithDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(253): /* window_clause */
|
|
fallthrough
|
|
case int32(309): /* windowdefn_list */
|
|
_sqlite3WindowListDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(266): /* idlist */
|
|
fallthrough
|
|
case int32(273): /* idlist_opt */
|
|
_sqlite3IdListDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(276): /* filter_over */
|
|
fallthrough
|
|
case int32(310): /* windowdefn */
|
|
fallthrough
|
|
case int32(311): /* window */
|
|
fallthrough
|
|
case int32(312): /* frame_opt */
|
|
fallthrough
|
|
case int32(315): /* over_clause */
|
|
_sqlite3WindowDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(289): /* trigger_cmd_list */
|
|
fallthrough
|
|
case int32(294): /* trigger_cmd */
|
|
_sqlite3DeleteTriggerStep(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, *(*uintptr)(unsafe.Pointer(yypminor)))
|
|
case int32(291): /* trigger_event */
|
|
_sqlite3IdListDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, (*(*TTrigEvent)(unsafe.Pointer(yypminor))).Fb)
|
|
case int32(317): /* frame_bound */
|
|
fallthrough
|
|
case int32(318): /* frame_bound_s */
|
|
fallthrough
|
|
case int32(319): /* frame_bound_e */
|
|
_sqlite3ExprDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, (*(*TFrameBound)(unsafe.Pointer(yypminor))).FpExpr)
|
|
break
|
|
/********* End destructor definitions *****************************************/
|
|
fallthrough
|
|
default:
|
|
break /* If no destructor action specified: do nothing */
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find the appropriate action for a parser given the non-terminal
|
|
// ** look-ahead token iLookAhead.
|
|
// */
|
|
func _yy_find_reduce_action(tls *libc.TLS, stateno uint16, iLookAhead uint16) (r uint16) {
|
|
var i int32
|
|
_ = i
|
|
i = int32(_yy_reduce_ofst[stateno])
|
|
i = i + libc.Int32FromUint16(iLookAhead)
|
|
return _yy_action[i]
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find the appropriate action for a parser given the terminal
|
|
// ** look-ahead token iLookAhead.
|
|
// */
|
|
func _yy_find_shift_action(tls *libc.TLS, iLookAhead uint16, stateno uint16) (r uint16) {
|
|
var i, j int32
|
|
var iFallback uint16
|
|
_, _, _ = i, iFallback, j
|
|
if libc.Int32FromUint16(stateno) > int32(YY_MAX_SHIFT) {
|
|
return stateno
|
|
}
|
|
for cond := true; cond; cond = int32(1) != 0 {
|
|
i = libc.Int32FromUint16(_yy_shift_ofst[stateno])
|
|
i = i + libc.Int32FromUint16(iLookAhead)
|
|
if libc.Int32FromUint16(_yy_lookahead[i]) != libc.Int32FromUint16(iLookAhead) { /* Fallback token */
|
|
iFallback = _yyFallback[iLookAhead]
|
|
if libc.Int32FromUint16(iFallback) != 0 {
|
|
/* Fallback loop must terminate */
|
|
iLookAhead = iFallback
|
|
continue
|
|
}
|
|
j = i - libc.Int32FromUint16(iLookAhead) + int32(YYWILDCARD)
|
|
if libc.Int32FromUint16(_yy_lookahead[j]) == int32(YYWILDCARD) && libc.Int32FromUint16(iLookAhead) > 0 {
|
|
return _yy_action[j]
|
|
}
|
|
return _yy_default[stateno]
|
|
} else {
|
|
return _yy_action[i]
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The journal file must be open when this function is called.
|
|
// **
|
|
// ** This function is a no-op if the journal file has not been written to
|
|
// ** within the current transaction (i.e. if Pager.journalOff==0).
|
|
// **
|
|
// ** If doTruncate is non-zero or the Pager.journalSizeLimit variable is
|
|
// ** set to 0, then truncate the journal file to zero bytes in size. Otherwise,
|
|
// ** zero the 28-byte header at the start of the journal file. In either case,
|
|
// ** if the pager is not in no-sync mode, sync the journal file immediately
|
|
// ** after writing or truncating it.
|
|
// **
|
|
// ** If Pager.journalSizeLimit is set to a positive, non-zero value, and
|
|
// ** following the truncation or zeroing described above the size of the
|
|
// ** journal file in bytes is larger than this value, then truncate the
|
|
// ** journal file to Pager.journalSizeLimit bytes. The journal file does
|
|
// ** not need to be synced following this operation.
|
|
// **
|
|
// ** If an IO error occurs, abandon processing and return the IO error code.
|
|
// ** Otherwise, return SQLITE_OK.
|
|
// */
|
|
func _zeroJournalHdr(tls *libc.TLS, pPager uintptr, doTruncate int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iLimit Ti64
|
|
var rc int32
|
|
var _ /* sz at bp+0 */ Ti64
|
|
_, _ = iLimit, rc
|
|
rc = SQLITE_OK /* Return code */
|
|
if (*TPager)(unsafe.Pointer(pPager)).FjournalOff != 0 {
|
|
iLimit = (*TPager)(unsafe.Pointer(pPager)).FjournalSizeLimit /* Local cache of jsl */
|
|
if doTruncate != 0 || iLimit == 0 {
|
|
rc = _sqlite3OsTruncate(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, 0)
|
|
} else {
|
|
rc = _sqlite3OsWrite(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, uintptr(unsafe.Pointer(&_zeroHdr)), int32(28), 0)
|
|
}
|
|
if rc == SQLITE_OK && !((*TPager)(unsafe.Pointer(pPager)).FnoSync != 0) {
|
|
rc = _sqlite3OsSync(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, int32(SQLITE_SYNC_DATAONLY)|libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FsyncFlags))
|
|
}
|
|
/* At this point the transaction is committed but the write lock
|
|
** is still held on the file. If there is a size limit configured for
|
|
** the persistent journal and the journal file currently consumes more
|
|
** space than that limit allows for, truncate it now. There is no need
|
|
** to sync the file following this operation.
|
|
*/
|
|
if rc == SQLITE_OK && iLimit > 0 {
|
|
rc = _sqlite3OsFileSize(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, bp)
|
|
if rc == SQLITE_OK && **(**Ti64)(__ccgo_up(bp)) > iLimit {
|
|
rc = _sqlite3OsTruncate(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iLimit)
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The zeroblob(N) function returns a zero-filled blob of size N bytes.
|
|
// */
|
|
func _zeroblobFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var n Ti64
|
|
var rc int32
|
|
_, _ = n, rc
|
|
_ = argc
|
|
n = Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if n < 0 {
|
|
n = 0
|
|
}
|
|
rc = Xsqlite3_result_zeroblob64(tls, context, libc.Uint64FromInt64(n)) /* IMP: R-00293-64994 */
|
|
if rc != 0 {
|
|
Xsqlite3_result_error_code(tls, context, rc)
|
|
}
|
|
}
|
|
|
|
type blkcnt_t = Tblkcnt_t
|
|
|
|
type blksize_t = Tblksize_t
|
|
|
|
type clockid_t = Tclockid_t
|
|
|
|
type double_t = Tdouble_t
|
|
|
|
const fdatasync = 0
|
|
|
|
type finder_type = Tfinder_type
|
|
|
|
/****************************************************************************
|
|
**************************** sqlite3_vfs methods ****************************
|
|
**
|
|
** This division contains the implementation of methods on the
|
|
** sqlite3_vfs object.
|
|
*/
|
|
|
|
type flock = Tflock
|
|
|
|
type id_t = Tid_t
|
|
|
|
func init() {
|
|
p := unsafe.Pointer(&_nolockIoFinder)
|
|
*(*uintptr)(unsafe.Add(p, 0)) = __ccgo_fp(_nolockIoFinderImpl)
|
|
}
|
|
|
|
func init() {
|
|
p := unsafe.Pointer(&_posixIoFinder)
|
|
*(*uintptr)(unsafe.Add(p, 0)) = __ccgo_fp(_posixIoFinderImpl)
|
|
}
|
|
|
|
type itimerval = Titimerval
|
|
|
|
type key_t = Tkey_t
|
|
|
|
type nlink_t = Tnlink_t
|
|
|
|
type quad_t = Tquad_t
|
|
|
|
type sigset_t = Tsigset_t
|
|
|
|
type stat = Tstat
|
|
|
|
const static_assert = 0
|
|
|
|
type suseconds_t = Tsuseconds_t
|
|
|
|
const threadid = 0
|
|
|
|
type u_int16_t = Tu_int16_t
|
|
|
|
type u_int32_t = Tu_int32_t
|
|
|
|
type u_int64_t = Tu_int64_t
|
|
|
|
type u_int8_t = Tu_int8_t
|
|
|
|
type u_quad_t = Tu_quad_t
|
|
|
|
type uint = Tuint
|
|
|
|
type unixFile = TunixFile
|
|
|
|
type unixFileId = TunixFileId
|
|
|
|
type unixInodeInfo = TunixInodeInfo
|
|
|
|
type unixShm = TunixShm
|
|
|
|
type unixShmNode = TunixShmNode
|
|
|
|
type unix_syscall = Tunix_syscall
|
|
|
|
type ushort = Tushort
|
|
|
|
type vxworksFileId = TvxworksFileId
|
|
|
|
/*************** End of Unique File ID Utility Used By VxWorks ****************
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
*************************** Posix Advisory Locking ****************************
|
|
**
|
|
** POSIX advisory locks are broken by design. ANSI STD 1003.1 (1996)
|
|
** section 6.5.2.2 lines 483 through 490 specify that when a process
|
|
** sets or clears a lock, that operation overrides any prior locks set
|
|
** by the same process. It does not explicitly say so, but this implies
|
|
** that it overrides locks set by the same process using a different
|
|
** file descriptor. Consider this test case:
|
|
**
|
|
** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
|
|
** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
|
|
**
|
|
** Suppose ./file1 and ./file2 are really the same file (because
|
|
** one is a hard or symbolic link to the other) then if you set
|
|
** an exclusive lock on fd1, then try to get an exclusive lock
|
|
** on fd2, it works. I would have expected the second lock to
|
|
** fail since there was already a lock on the file due to fd1.
|
|
** But not so. Since both locks came from the same process, the
|
|
** second overrides the first, even though they were on different
|
|
** file descriptors opened on different file names.
|
|
**
|
|
** This means that we cannot use POSIX locks to synchronize file access
|
|
** among competing threads of the same process. POSIX locks will work fine
|
|
** to synchronize access for threads in separate processes, but not
|
|
** threads within the same process.
|
|
**
|
|
** To work around the problem, SQLite has to manage file locks internally
|
|
** on its own. Whenever a new database is opened, we have to find the
|
|
** specific inode of the database file (the inode is determined by the
|
|
** st_dev and st_ino fields of the stat structure that fstat() fills in)
|
|
** and check for locks already existing on that inode. When locks are
|
|
** created or removed, we have to look at our own internal record of the
|
|
** locks to see if another thread has previously set a lock on that same
|
|
** inode.
|
|
**
|
|
** (Aside: The use of inode numbers as unique IDs does not work on VxWorks.
|
|
** For VxWorks, we have to use the alternative unique ID system based on
|
|
** canonical filename and implemented in the previous division.)
|
|
**
|
|
** The sqlite3_file structure for POSIX is no longer just an integer file
|
|
** descriptor. It is now a structure that holds the integer file
|
|
** descriptor and a pointer to a structure that describes the internal
|
|
** locks on the corresponding inode. There is one locking structure
|
|
** per inode, so if the same inode is opened twice, both unixFile structures
|
|
** point to the same locking structure. The locking structure keeps
|
|
** a reference count (so we will know when to delete it) and a "cnt"
|
|
** field that tells us its internal lock status. cnt==0 means the
|
|
** file is unlocked. cnt==-1 means the file has an exclusive lock.
|
|
** cnt>0 means there are cnt shared locks on the file.
|
|
**
|
|
** Any attempt to lock or unlock a file first checks the locking
|
|
** structure. The fcntl() system call is only invoked to set a
|
|
** POSIX lock if the internal lock structure transitions between
|
|
** a locked and an unlocked state.
|
|
**
|
|
** But wait: there are yet more problems with POSIX advisory locks.
|
|
**
|
|
** If you close a file descriptor that points to a file that has locks,
|
|
** all locks on that file that are owned by the current process are
|
|
** released. To work around this problem, each unixInodeInfo object
|
|
** maintains a count of the number of pending locks on the inode.
|
|
** When an attempt is made to close an unixFile, if there are
|
|
** other unixFile open on the same inode that are holding locks, the call
|
|
** to close() the file descriptor is deferred until all of the locks clear.
|
|
** The unixInodeInfo structure keeps a list of file descriptors that need to
|
|
** be closed and that list is walked (and cleared) when the last lock
|
|
** clears.
|
|
**
|
|
** Yet another problem: LinuxThreads do not play well with posix locks.
|
|
**
|
|
** Many older versions of linux use the LinuxThreads library which is
|
|
** not posix compliant. Under LinuxThreads, a lock created by thread
|
|
** A cannot be modified or overridden by a different thread B.
|
|
** Only thread A can modify the lock. Locking behavior is correct
|
|
** if the application uses the newer Native Posix Thread Library (NPTL)
|
|
** on linux - with NPTL a lock created by thread A can override locks
|
|
** in thread B. But there is no way to know at compile-time which
|
|
** threading library is being used. So there is no way to know at
|
|
** compile-time whether or not thread A can override locks on thread B.
|
|
** One has to do a run-time check to discover the behavior of the
|
|
** current process.
|
|
**
|
|
** SQLite used to support LinuxThreads. But support for LinuxThreads
|
|
** was dropped beginning with version 3.7.0. SQLite will still work with
|
|
** LinuxThreads provided that (1) there is no more than one connection
|
|
** per database file in the same process and (2) database connections
|
|
** do not move across threads.
|
|
*/
|
|
|
|
type winsize = Twinsize
|