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>
1235 lines
46 KiB
Go
1235 lines
46 KiB
Go
// Code generated by modernc.org/undup from the per-target sqlite_*.go files; DO NOT EDIT.
|
|
|
|
//go:build (netbsd && amd64) || (openbsd && amd64) || (openbsd && arm64)
|
|
|
|
package sqlite3
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"modernc.org/libc"
|
|
)
|
|
|
|
const CHAR_BIT = 8
|
|
|
|
const CLOCKS_PER_SEC = 100
|
|
|
|
const CLOCK_MONOTONIC = 3
|
|
|
|
const DL_GETERRNO = 1
|
|
|
|
const DL_LAZY = 1
|
|
|
|
const INT_MAX = 2147483647
|
|
|
|
const INT_MIN = -2147483648
|
|
|
|
const IOCPARM_MAX = 0
|
|
|
|
const LLONG_MAX = 9223372036854775807
|
|
|
|
const LLONG_MIN = -9223372036854775808
|
|
|
|
const LONG_BIT = 64
|
|
|
|
const LONG_MAX = 9223372036854775807
|
|
|
|
const LONG_MIN = -9223372036854775808
|
|
|
|
const MADV_FREE = 6
|
|
|
|
const MADV_SPACEAVAIL = 5
|
|
|
|
const MAP_INHERIT_COPY = 1
|
|
|
|
const MAP_INHERIT_NONE = 2
|
|
|
|
const MAP_INHERIT_SHARE = 0
|
|
|
|
const QUAD_MAX = 9223372036854775807
|
|
|
|
const QUAD_MIN = -9223372036854775808
|
|
|
|
const SCHAR_MAX = 127
|
|
|
|
const SCHAR_MIN = -128
|
|
|
|
const SHRT_MAX = 32767
|
|
|
|
const SHRT_MIN = -32768
|
|
|
|
const SIZE_T_MAX = 18446744073709551615
|
|
|
|
const STRIPDISC = 6
|
|
|
|
const TIOCFLAG_CLOCAL = 2
|
|
|
|
const TIOCFLAG_CRTSCTS = 4
|
|
|
|
const TIOCFLAG_MDMBUF = 8
|
|
|
|
const TIOCFLAG_SOFTCAR = 1
|
|
|
|
type Tcpuid_t = uint64
|
|
|
|
type Tqdiv_t = struct {
|
|
Fquot Tquad_t
|
|
Frem Tquad_t
|
|
}
|
|
|
|
type Ttimer_t = int32
|
|
|
|
type Tunchar = uint8
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The unixFile structure is subclass of sqlite3_file specific to the unix
|
|
// ** VFS implementations.
|
|
// */
|
|
type TunixFile = struct {
|
|
FpMethod uintptr
|
|
FpVfs uintptr
|
|
FpInode uintptr
|
|
Fh int32
|
|
FeFileLock uint8
|
|
FctrlFlags uint16
|
|
FlastErrno int32
|
|
FlockingContext uintptr
|
|
FpPreallocatedUnused uintptr
|
|
FzPath uintptr
|
|
FpShm uintptr
|
|
FszChunk int32
|
|
FsectorSize int32
|
|
FdeviceCharacteristics int32
|
|
}
|
|
|
|
const UCHAR_MAX = 255
|
|
|
|
const UINT_MAX = 4294967295
|
|
|
|
const ULLONG_MAX = 18446744073709551615
|
|
|
|
const ULONG_MAX = 18446744073709551615
|
|
|
|
const UQUAD_MAX = 18446744073709551615
|
|
|
|
const USHRT_MAX = 65535
|
|
|
|
const WORD_BIT = 32
|
|
|
|
const _BIG_ENDIAN = 4321
|
|
|
|
const _LITTLE_ENDIAN = 1234
|
|
|
|
const _SC_FSYNC = 29
|
|
|
|
const _SC_PAGESIZE = 28
|
|
|
|
const _SC_PAGE_SIZE = 28
|
|
|
|
const _SC_XOPEN_SHM = 30
|
|
|
|
const __BEGIN_DECLS = 0
|
|
|
|
const __BEGIN_HIDDEN_DECLS = 0
|
|
|
|
const __BEGIN_PUBLIC_DECLS = 0
|
|
|
|
const __END_DECLS = 0
|
|
|
|
const __END_HIDDEN_DECLS = 0
|
|
|
|
const __END_PUBLIC_DECLS = 0
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function performs the parts of the "close file" operation
|
|
// ** common to all locking schemes. It closes the directory and file
|
|
// ** handles, if they are valid, and sets all fields of the unixFile
|
|
// ** structure to 0.
|
|
// **
|
|
// ** It is *not* necessary to hold the mutex when this routine is called,
|
|
// ** even on VxWorks. A mutex will be acquired on VxWorks by the
|
|
// ** vxworksReleaseFileId() routine.
|
|
// */
|
|
func _closeUnixFile(tls *libc.TLS, id uintptr) (r int32) {
|
|
var pFile uintptr
|
|
_ = pFile
|
|
pFile = id
|
|
if (*TunixFile)(unsafe.Pointer(pFile)).Fh >= 0 {
|
|
_robust_close(tls, pFile, (*TunixFile)(unsafe.Pointer(pFile)).Fh, int32(42509))
|
|
(*TunixFile)(unsafe.Pointer(pFile)).Fh = -int32(1)
|
|
}
|
|
Xsqlite3_free(tls, (*TunixFile)(unsafe.Pointer(pFile)).FpPreallocatedUnused)
|
|
libc.Xmemset(tls, pFile, 0, uint64(88))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// 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.
|
|
// **
|
|
// ** When the locking level reaches NO_LOCK, delete the lock file.
|
|
// */
|
|
func _dotlockUnlock(tls *libc.TLS, id uintptr, eFileLock int32) (r int32) {
|
|
var pFile, zLockFile uintptr
|
|
var rc, tErrno int32
|
|
_, _, _, _ = pFile, rc, tErrno, zLockFile
|
|
pFile = id
|
|
zLockFile = (*TunixFile)(unsafe.Pointer(pFile)).FlockingContext
|
|
/* no-op if possible */
|
|
if libc.Int32FromUint8((*TunixFile)(unsafe.Pointer(pFile)).FeFileLock) == eFileLock {
|
|
return SQLITE_OK
|
|
}
|
|
/* To downgrade to shared, simply update our internal notion of the
|
|
** lock state. No need to mess with the file on disk.
|
|
*/
|
|
if eFileLock == int32(SHARED_LOCK) {
|
|
(*TunixFile)(unsafe.Pointer(pFile)).FeFileLock = uint8(SHARED_LOCK)
|
|
return SQLITE_OK
|
|
}
|
|
/* To fully unlock the database, delete the lock file */
|
|
rc = (*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(19)].FpCurrent})))(tls, zLockFile)
|
|
if rc < 0 {
|
|
tErrno = **(**int32)(__ccgo_up(libc.X__errno(tls)))
|
|
if tErrno == int32(ENOENT) {
|
|
rc = SQLITE_OK
|
|
} else {
|
|
rc = libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(8)<<libc.Int32FromInt32(8)
|
|
_storeLastErrno(tls, pFile, tErrno)
|
|
}
|
|
return rc
|
|
}
|
|
(*TunixFile)(unsafe.Pointer(pFile)).FeFileLock = uint8(NO_LOCK)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Begin a read transaction on the WAL.
|
|
// **
|
|
// ** This routine used to be called "pagerOpenSnapshot()" because it essentially
|
|
// ** makes a snapshot of the database at the current point in time and preserves
|
|
// ** that snapshot for use by the reader in spite of concurrently changes by
|
|
// ** other writers or checkpointers.
|
|
// */
|
|
func _pagerBeginReadTransaction(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc int32
|
|
var _ /* changed at bp+0 */ int32
|
|
_ = rc /* Return code */
|
|
**(**int32)(__ccgo_up(bp)) = 0 /* True if cache must be reset */
|
|
/* sqlite3WalEndReadTransaction() was not called for the previous
|
|
** transaction in locking_mode=EXCLUSIVE. So call it now. If we
|
|
** are in locking_mode=NORMAL and EndRead() was previously called,
|
|
** the duplicate call is harmless.
|
|
*/
|
|
_sqlite3WalEndReadTransaction(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal)
|
|
rc = _sqlite3WalBeginReadTransaction(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal, bp)
|
|
if rc != SQLITE_OK || **(**int32)(__ccgo_up(bp)) != 0 {
|
|
_pager_reset(tls, pPager)
|
|
if 0 != 0 {
|
|
_sqlite3OsUnfetch(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, 0, uintptr(0))
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
|
|
// */
|
|
func _pagerFixMaplimit(tls *libc.TLS, pPager uintptr) {
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is a no-op if the pager is in exclusive mode and not
|
|
// ** in the ERROR state. Otherwise, it switches the pager to PAGER_OPEN
|
|
// ** state.
|
|
// **
|
|
// ** If the pager is not in exclusive-access mode, the database file is
|
|
// ** completely unlocked. If the file is unlocked and the file-system does
|
|
// ** not exhibit the UNDELETABLE_WHEN_OPEN property, the journal file is
|
|
// ** closed (if it is open).
|
|
// **
|
|
// ** If the pager is in ERROR state when this function is called, the
|
|
// ** contents of the pager cache are discarded before switching back to
|
|
// ** the OPEN state. Regardless of whether the pager is in exclusive-mode
|
|
// ** or not, any journal file left in the file-system will be treated
|
|
// ** as a hot-journal and rolled back the next time a read-transaction
|
|
// ** is opened (by this or by any other connection).
|
|
// */
|
|
func _pager_unlock(tls *libc.TLS, pPager uintptr) {
|
|
var iDc, rc, v1 int32
|
|
_, _, _ = iDc, rc, v1
|
|
_sqlite3BitvecDestroy(tls, (*TPager)(unsafe.Pointer(pPager)).FpInJournal)
|
|
(*TPager)(unsafe.Pointer(pPager)).FpInJournal = uintptr(0)
|
|
_releaseAllSavepoints(tls, pPager)
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_ERROR) {
|
|
/* If an IO error occurs in wal.c while attempting to wrap the wal file,
|
|
** then the Wal object may be holding a write-lock but no read-lock.
|
|
** This call ensures that the write-lock is dropped as well. We cannot
|
|
** have sqlite3WalEndReadTransaction() drop the write-lock, as it once
|
|
** did, because this would break "BEGIN EXCLUSIVE" handling for
|
|
** SQLITE_ENABLE_SETLK_TIMEOUT builds. */
|
|
_sqlite3WalEndWriteTransaction(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal)
|
|
}
|
|
_sqlite3WalEndReadTransaction(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal)
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_OPEN)
|
|
} else {
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0) {
|
|
if (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Ffd)).FpMethods != uintptr(0) {
|
|
v1 = _sqlite3OsDeviceCharacteristics(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd)
|
|
} else {
|
|
v1 = 0
|
|
} /* Error code returned by pagerUnlockDb() */
|
|
iDc = v1
|
|
/* If the operating system support deletion of open files, then
|
|
** close the journal file when dropping the database lock. Otherwise
|
|
** another connection with journal_mode=delete might delete the file
|
|
** out from under us.
|
|
*/
|
|
if 0 == iDc&int32(SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN) || int32(1) != libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode)&int32(5) {
|
|
_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
|
|
}
|
|
/* If the pager is in the ERROR state and the call to unlock the database
|
|
** file fails, set the current lock to UNKNOWN_LOCK. See the comment
|
|
** above the #define for UNKNOWN_LOCK for an explanation of why this
|
|
** is necessary.
|
|
*/
|
|
rc = _pagerUnlockDb(tls, pPager, NO_LOCK)
|
|
if rc != SQLITE_OK && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_ERROR) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FeLock = libc.Uint8FromInt32(libc.Int32FromInt32(EXCLUSIVE_LOCK) + libc.Int32FromInt32(1))
|
|
}
|
|
/* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here
|
|
** without clearing the error code. This is intentional - the error
|
|
** code is cleared and the cache reset in the block below.
|
|
*/
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_OPEN)
|
|
}
|
|
}
|
|
/* If Pager.errCode is set, the contents of the pager cache cannot be
|
|
** trusted. Now that there are no outstanding references to the pager,
|
|
** it can safely move back to PAGER_OPEN state. This happens in both
|
|
** normal and exclusive-locking mode.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FerrCode != 0 {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FtempFile) == 0 {
|
|
_pager_reset(tls, pPager)
|
|
(*TPager)(unsafe.Pointer(pPager)).FchangeCountDone = uint8(0)
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_OPEN)
|
|
} else {
|
|
if (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != uintptr(0) {
|
|
v1 = PAGER_OPEN
|
|
} else {
|
|
v1 = int32(PAGER_READER)
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FeState = libc.Uint8FromInt32(v1)
|
|
}
|
|
if 0 != 0 {
|
|
_sqlite3OsUnfetch(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, 0, uintptr(0))
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FerrCode = SQLITE_OK
|
|
_setGetterMethod(tls, pPager)
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = 0
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalHdr = 0
|
|
(*TPager)(unsafe.Pointer(pPager)).FsetSuper = uint8(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the Pager.xGet method for the appropriate routine used to fetch
|
|
// ** content from the pager.
|
|
// */
|
|
func _setGetterMethod(tls *libc.TLS, pPager uintptr) {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FerrCode != 0 {
|
|
(*TPager)(unsafe.Pointer(pPager)).FxGet = __ccgo_fp(_getPageError)
|
|
} else {
|
|
(*TPager)(unsafe.Pointer(pPager)).FxGet = __ccgo_fp(_getPageNormal)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The following singleton contains the global configuration for
|
|
// ** the SQLite library.
|
|
// */
|
|
var _sqlite3Config = TSqlite3Config{
|
|
FbCoreMutex: uint8(1),
|
|
FbFullMutex: libc.BoolUint8(true),
|
|
FbUseCis: uint8(SQLITE_ALLOW_COVERING_INDEX_SCAN),
|
|
FbExtraSchemaChecks: uint8(1),
|
|
FmxStrlen: int32(0x7ffffffe),
|
|
FszLookaside: int32(1200),
|
|
FnLookaside: int32(40),
|
|
FnStmtSpill: libc.Int32FromInt32(64) * libc.Int32FromInt32(1024),
|
|
FnPage: int32(SQLITE_DEFAULT_PCACHE_INITSZ),
|
|
FszPma: uint32(SQLITE_SORTER_PMASZ),
|
|
FmxMemdbSize: int64(SQLITE_MEMDB_DEFAULT_MAXSIZE),
|
|
FiOnceResetThreshold: int32(0x7ffffffe),
|
|
FszSorterRef: uint32(SQLITE_DEFAULT_SORTERREF_SIZE),
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* No-op stubs to use when memory-mapped I/O is disabled */
|
|
func _sqlite3OsFetch(tls *libc.TLS, id uintptr, iOff Ti64, iAmt int32, pp uintptr) (r int32) {
|
|
**(**uintptr)(__ccgo_up(pp)) = uintptr(0)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
func _sqlite3OsUnfetch(tls *libc.TLS, id uintptr, iOff Ti64, p uintptr) (r int32) {
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine checks if there is a RESERVED lock held on the specified
|
|
// ** file by this or any other process. If such a lock is held, set *pResOut
|
|
// ** to a non-zero value otherwise *pResOut is set to zero. The return value
|
|
// ** is set to SQLITE_OK unless an I/O error occurs during lock checking.
|
|
// */
|
|
func _unixCheckReservedLock(tls *libc.TLS, id uintptr, pResOut uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var pFile uintptr
|
|
var rc, reserved int32
|
|
var _ /* lock at bp+0 */ Tflock
|
|
_, _, _ = pFile, rc, reserved
|
|
rc = SQLITE_OK
|
|
reserved = 0
|
|
pFile = id
|
|
Xsqlite3_mutex_enter(tls, (*TunixInodeInfo)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pFile)).FpInode)).FpLockMutex)
|
|
/* Check if a thread in this process holds such a lock */
|
|
if libc.Int32FromUint8((*TunixInodeInfo)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pFile)).FpInode)).FeFileLock) > int32(SHARED_LOCK) {
|
|
reserved = int32(1)
|
|
}
|
|
/* Otherwise see if some other process holds it.
|
|
*/
|
|
if !(reserved != 0) && !((*TunixInodeInfo)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pFile)).FpInode)).FbProcessLock != 0) {
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_whence = SEEK_SET
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_start = int64(_sqlite3PendingByte + libc.Int32FromInt32(1))
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_len = int64(1)
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_type = int16(F_WRLCK)
|
|
if (*(*func(*libc.TLS, int32, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(7)].FpCurrent})))(tls, (*TunixFile)(unsafe.Pointer(pFile)).Fh, int32(F_GETLK), libc.VaList(bp+32, bp)) != 0 {
|
|
rc = libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(14)<<libc.Int32FromInt32(8)
|
|
_storeLastErrno(tls, pFile, **(**int32)(__ccgo_up(libc.X__errno(tls))))
|
|
} else {
|
|
if int32((**(**Tflock)(__ccgo_up(bp))).Fl_type) != int32(F_UNLCK) {
|
|
reserved = int32(1)
|
|
}
|
|
}
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*TunixInodeInfo)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pFile)).FpInode)).FpLockMutex)
|
|
**(**int32)(__ccgo_up(pResOut)) = reserved
|
|
return rc
|
|
}
|
|
|
|
/*
|
|
** Set a posix-advisory-lock.
|
|
**
|
|
** There are two versions of this routine. If compiled with
|
|
** SQLITE_ENABLE_SETLK_TIMEOUT then the routine has an extra parameter
|
|
** which is a pointer to a unixFile. If the unixFile->iBusyTimeout
|
|
** value is set, then it is the number of milliseconds to wait before
|
|
** failing the lock. The iBusyTimeout value is always reset back to
|
|
** zero on each call.
|
|
**
|
|
** If SQLITE_ENABLE_SETLK_TIMEOUT is not defined, then do a non-blocking
|
|
** attempt to set the lock.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Use F_GETLK to check whether or not there are any readers with open
|
|
// ** wal-mode transactions in other processes on database file pFile. If
|
|
// ** no error occurs, return SQLITE_OK and set (*piOut) to 1 if there are
|
|
// ** such transactions, or 0 otherwise. If an error occurs, return an
|
|
// ** SQLite error code. The final value of *piOut is undefined in this
|
|
// ** case.
|
|
// */
|
|
func _unixFcntlExternalReader(tls *libc.TLS, pFile uintptr, piOut uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var pShmNode uintptr
|
|
var rc int32
|
|
var _ /* f at bp+0 */ Tflock
|
|
_, _ = pShmNode, rc
|
|
rc = SQLITE_OK
|
|
**(**int32)(__ccgo_up(piOut)) = 0
|
|
if (*TunixFile)(unsafe.Pointer(pFile)).FpShm != 0 {
|
|
pShmNode = (*TunixShm)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pFile)).FpShm)).FpShmNode
|
|
libc.Xmemset(tls, bp, 0, uint64(24))
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_type = int16(F_WRLCK)
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_whence = SEEK_SET
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_start = int64((libc.Int32FromInt32(22)+libc.Int32FromInt32(SQLITE_SHM_NLOCK))*libc.Int32FromInt32(4) + libc.Int32FromInt32(3))
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_len = int64(libc.Int32FromInt32(SQLITE_SHM_NLOCK) - libc.Int32FromInt32(3))
|
|
Xsqlite3_mutex_enter(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex)
|
|
if (*(*func(*libc.TLS, int32, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(7)].FpCurrent})))(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm, int32(F_GETLK), libc.VaList(bp+32, bp)) < 0 {
|
|
rc = libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(15)<<libc.Int32FromInt32(8)
|
|
} else {
|
|
**(**int32)(__ccgo_up(piOut)) = libc.BoolInt32(int32((**(**Tflock)(__ccgo_up(bp))).Fl_type) != int32(F_UNLCK))
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If possible, return a pointer to a mapping of file fd starting at offset
|
|
// ** iOff. The mapping must be valid for at least nAmt bytes.
|
|
// **
|
|
// ** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
|
|
// ** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
|
|
// ** Finally, if an error does occur, return an SQLite error code. The final
|
|
// ** value of *pp is undefined in this case.
|
|
// **
|
|
// ** If this function does return a pointer, the caller must eventually
|
|
// ** release the reference by calling unixUnfetch().
|
|
// */
|
|
func _unixFetch(tls *libc.TLS, fd uintptr, iOff Ti64, nAmt int32, pp uintptr) (r int32) {
|
|
**(**uintptr)(__ccgo_up(pp)) = uintptr(0)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The xGetLastError() method is designed to return a better
|
|
// ** low-level error message when operating-system problems come up
|
|
// ** during SQLite operation. Only the integer return code is currently
|
|
// ** used.
|
|
// */
|
|
func _unixGetLastError(tls *libc.TLS, NotUsed uintptr, NotUsed2 int32, NotUsed3 uintptr) (r int32) {
|
|
_ = NotUsed
|
|
_ = NotUsed2
|
|
_ = NotUsed3
|
|
return **(**int32)(__ccgo_up(libc.X__errno(tls)))
|
|
}
|
|
|
|
/*
|
|
************************ End of sqlite3_vfs methods ***************************
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
************************** Begin Proxy Locking ********************************
|
|
**
|
|
** Proxy locking is a "uber-locking-method" in this sense: It uses the
|
|
** other locking methods on secondary lock files. Proxy locking is a
|
|
** meta-layer over top of the primitive locking implemented above. For
|
|
** this reason, the division that implements of proxy locking is deferred
|
|
** until late in the file (here) after all of the other I/O methods have
|
|
** been defined - so that the primitive locking methods are available
|
|
** as services to help with the implementation of proxy locking.
|
|
**
|
|
****
|
|
**
|
|
** The default locking schemes in SQLite use byte-range locks on the
|
|
** database file to coordinate safe, concurrent access by multiple readers
|
|
** and writers [http://sqlite.org/lockingv3.html]. The five file locking
|
|
** states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented
|
|
** as POSIX read & write locks over fixed set of locations (via fsctl),
|
|
** on AFP and SMB only exclusive byte-range locks are available via fsctl
|
|
** with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states.
|
|
** To simulate a F_RDLCK on the shared range, on AFP a randomly selected
|
|
** address in the shared range is taken for a SHARED lock, the entire
|
|
** shared range is taken for an EXCLUSIVE lock):
|
|
**
|
|
** PENDING_BYTE 0x40000000
|
|
** RESERVED_BYTE 0x40000001
|
|
** SHARED_RANGE 0x40000002 -> 0x40000200
|
|
**
|
|
** This works well on the local file system, but shows a nearly 100x
|
|
** slowdown in read performance on AFP because the AFP client disables
|
|
** the read cache when byte-range locks are present. Enabling the read
|
|
** cache exposes a cache coherency problem that is present on all OS X
|
|
** supported network file systems. NFS and AFP both observe the
|
|
** close-to-open semantics for ensuring cache coherency
|
|
** [http://nfs.sourceforge.net/#faq_a8], which does not effectively
|
|
** address the requirements for concurrent database access by multiple
|
|
** readers and writers
|
|
** [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html].
|
|
**
|
|
** To address the performance and cache coherency issues, proxy file locking
|
|
** changes the way database access is controlled by limiting access to a
|
|
** single host at a time and moving file locks off of the database file
|
|
** and onto a proxy file on the local file system.
|
|
**
|
|
**
|
|
** Using proxy locks
|
|
** -----------------
|
|
**
|
|
** C APIs
|
|
**
|
|
** sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE,
|
|
** <proxy_path> | ":auto:");
|
|
** sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE,
|
|
** &<proxy_path>);
|
|
**
|
|
**
|
|
** SQL pragmas
|
|
**
|
|
** PRAGMA [database.]lock_proxy_file=<proxy_path> | :auto:
|
|
** PRAGMA [database.]lock_proxy_file
|
|
**
|
|
** Specifying ":auto:" means that if there is a conch file with a matching
|
|
** host ID in it, the proxy path in the conch file will be used, otherwise
|
|
** a proxy path based on the user's temp dir
|
|
** (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the
|
|
** actual proxy file name is generated from the name and path of the
|
|
** database file. For example:
|
|
**
|
|
** For database path "/Users/me/foo.db"
|
|
** The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:")
|
|
**
|
|
** Once a lock proxy is configured for a database connection, it can not
|
|
** be removed, however it may be switched to a different proxy path via
|
|
** the above APIs (assuming the conch file is not being held by another
|
|
** connection or process).
|
|
**
|
|
**
|
|
** How proxy locking works
|
|
** -----------------------
|
|
**
|
|
** Proxy file locking relies primarily on two new supporting files:
|
|
**
|
|
** * conch file to limit access to the database file to a single host
|
|
** at a time
|
|
**
|
|
** * proxy file to act as a proxy for the advisory locks normally
|
|
** taken on the database
|
|
**
|
|
** The conch file - to use a proxy file, sqlite must first "hold the conch"
|
|
** by taking an sqlite-style shared lock on the conch file, reading the
|
|
** contents and comparing the host's unique host ID (see below) and lock
|
|
** proxy path against the values stored in the conch. The conch file is
|
|
** stored in the same directory as the database file and the file name
|
|
** is patterned after the database file name as ".<databasename>-conch".
|
|
** If the conch file does not exist, or its contents do not match the
|
|
** host ID and/or proxy path, then the lock is escalated to an exclusive
|
|
** lock and the conch file contents is updated with the host ID and proxy
|
|
** path and the lock is downgraded to a shared lock again. If the conch
|
|
** is held by another process (with a shared lock), the exclusive lock
|
|
** will fail and SQLITE_BUSY is returned.
|
|
**
|
|
** The proxy file - a single-byte file used for all advisory file locks
|
|
** normally taken on the database file. This allows for safe sharing
|
|
** of the database file for multiple readers and writers on the same
|
|
** host (the conch ensures that they all use the same local lock file).
|
|
**
|
|
** Requesting the lock proxy does not immediately take the conch, it is
|
|
** only taken when the first request to lock database file is made.
|
|
** This matches the semantics of the traditional locking behavior, where
|
|
** opening a connection to a database file does not take a lock on it.
|
|
** The shared lock and an open file descriptor are maintained until
|
|
** the connection to the database is closed.
|
|
**
|
|
** The proxy file and the lock file are never deleted so they only need
|
|
** to be created the first time they are used.
|
|
**
|
|
** Configuration options
|
|
** ---------------------
|
|
**
|
|
** SQLITE_PREFER_PROXY_LOCKING
|
|
**
|
|
** Database files accessed on non-local file systems are
|
|
** automatically configured for proxy locking, lock files are
|
|
** named automatically using the same logic as
|
|
** PRAGMA lock_proxy_file=":auto:"
|
|
**
|
|
** SQLITE_PROXY_DEBUG
|
|
**
|
|
** Enables the logging of error messages during host id file
|
|
** retrieval and creation
|
|
**
|
|
** LOCKPROXYDIR
|
|
**
|
|
** Overrides the default directory used for lock proxy files that
|
|
** are named automatically via the ":auto:" setting
|
|
**
|
|
** SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
|
|
**
|
|
** Permissions to use when creating a directory for storing the
|
|
** lock proxy files, only used when LOCKPROXYDIR is not set.
|
|
**
|
|
**
|
|
** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING,
|
|
** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will
|
|
** force proxy locking to be used for every database file opened, and 0
|
|
** will force automatic proxy locking to be disabled for all database
|
|
** files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or
|
|
** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING).
|
|
*/
|
|
|
|
/*
|
|
** Proxy locking is only available on MacOSX
|
|
*/
|
|
/*
|
|
** The proxy locking style is intended for use with AFP filesystems.
|
|
** And since AFP is only supported on MacOSX, the proxy locking is also
|
|
** restricted to MacOSX.
|
|
**
|
|
**
|
|
******************* End of the proxy lock implementation **********************
|
|
******************************************************************************/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If pFile has a -shm file open and it is sharing that file with some
|
|
// ** other connection, either in the same process or in a separate process,
|
|
// ** then return true. Return false if either pFile does not have a -shm
|
|
// ** file open or if it is the only connection to that -shm file across the
|
|
// ** entire system.
|
|
// **
|
|
// ** This routine is not required for correct operation. It can always return
|
|
// ** false and SQLite will continue to operate according to spec. However,
|
|
// ** when this routine does its job, it adds extra robustness in cases
|
|
// ** where database file locks have been erroneously deleted in a WAL-mode
|
|
// ** database by doing close(open(DATABASE_PATHNAME)) or similar.
|
|
// **
|
|
// ** With false negatives, SQLite still operates to spec, though with less
|
|
// ** robustness. With false positives, the last database connection on a
|
|
// ** WAL-mode database will fail to unlink the -wal and -shm files, which
|
|
// ** is annoying but harmless. False positives will also prevent a database
|
|
// ** connection from running "PRAGMA journal_mode=DELETE" in order to take
|
|
// ** the database out of WAL mode, which is perhaps more serious, but is
|
|
// ** still not a disaster.
|
|
// */
|
|
func _unixIsSharingShmNode(tls *libc.TLS, pFile uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var pShmNode uintptr
|
|
var _ /* lock at bp+0 */ Tflock
|
|
_ = pShmNode
|
|
if (*TunixFile)(unsafe.Pointer(pFile)).FpShm == uintptr(0) {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint16((*TunixFile)(unsafe.Pointer(pFile)).FctrlFlags)&int32(UNIXFILE_EXCL) != 0 {
|
|
return 0
|
|
}
|
|
pShmNode = (*TunixShm)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pFile)).FpShm)).FpShmNode
|
|
libc.Xmemset(tls, bp, 0, uint64(24))
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_whence = SEEK_SET
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_start = int64((libc.Int32FromInt32(22)+libc.Int32FromInt32(SQLITE_SHM_NLOCK))*libc.Int32FromInt32(4) + libc.Int32FromInt32(SQLITE_SHM_NLOCK))
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_len = int64(1)
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_type = int16(F_WRLCK)
|
|
(*(*func(*libc.TLS, int32, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(7)].FpCurrent})))(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm, int32(F_GETLK), libc.VaList(bp+32, bp))
|
|
return libc.BoolInt32(int32((**(**Tflock)(__ccgo_up(bp))).Fl_type) != int32(F_UNLCK))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Lock the file with the lock specified by parameter eFileLock - one
|
|
// ** of the following:
|
|
// **
|
|
// ** (1) SHARED_LOCK
|
|
// ** (2) RESERVED_LOCK
|
|
// ** (3) PENDING_LOCK
|
|
// ** (4) EXCLUSIVE_LOCK
|
|
// **
|
|
// ** Sometimes when requesting one lock state, additional lock states
|
|
// ** are inserted in between. The locking might fail on one of the later
|
|
// ** transitions leaving the lock state different from what it started but
|
|
// ** still short of its goal. The following chart shows the allowed
|
|
// ** transitions and the inserted intermediate states:
|
|
// **
|
|
// ** UNLOCKED -> SHARED
|
|
// ** SHARED -> RESERVED
|
|
// ** SHARED -> EXCLUSIVE
|
|
// ** RESERVED -> (PENDING) -> EXCLUSIVE
|
|
// ** PENDING -> EXCLUSIVE
|
|
// **
|
|
// ** This routine will only increase a lock. Use the sqlite3OsUnlock()
|
|
// ** routine to lower a locking level.
|
|
// */
|
|
func _unixLock(tls *libc.TLS, id uintptr, eFileLock int32) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var pFile, pInode uintptr
|
|
var rc, tErrno, v1 int32
|
|
var _ /* lock at bp+0 */ Tflock
|
|
_, _, _, _, _ = pFile, pInode, rc, tErrno, v1
|
|
/* The following describes the implementation of the various locks and
|
|
** lock transitions in terms of the POSIX advisory shared and exclusive
|
|
** lock primitives (called read-locks and write-locks below, to avoid
|
|
** confusion with SQLite lock names). The algorithms are complicated
|
|
** slightly in order to be compatible with Windows95 systems simultaneously
|
|
** accessing the same database file, in case that is ever required.
|
|
**
|
|
** Symbols defined in os.h identify the 'pending byte' and the 'reserved
|
|
** byte', each single bytes at well known offsets, and the 'shared byte
|
|
** range', a range of 510 bytes at a well known offset.
|
|
**
|
|
** To obtain a SHARED lock, a read-lock is obtained on the 'pending
|
|
** byte'. If this is successful, 'shared byte range' is read-locked
|
|
** and the lock on the 'pending byte' released. (Legacy note: When
|
|
** SQLite was first developed, Windows95 systems were still very common,
|
|
** and Windows95 lacks a shared-lock capability. So on Windows95, a
|
|
** single randomly selected by from the 'shared byte range' is locked.
|
|
** Windows95 is now pretty much extinct, but this work-around for the
|
|
** lack of shared-locks on Windows95 lives on, for backwards
|
|
** compatibility.)
|
|
**
|
|
** A process may only obtain a RESERVED lock after it has a SHARED lock.
|
|
** A RESERVED lock is implemented by grabbing a write-lock on the
|
|
** 'reserved byte'.
|
|
**
|
|
** An EXCLUSIVE lock may only be requested after either a SHARED or
|
|
** RESERVED lock is held. An EXCLUSIVE lock is implemented by obtaining
|
|
** a write-lock on the entire 'shared byte range'. Since all other locks
|
|
** require a read-lock on one of the bytes within this range, this ensures
|
|
** that no other locks are held on the database.
|
|
**
|
|
** If a process that holds a RESERVED lock requests an EXCLUSIVE, then
|
|
** a PENDING lock is obtained first. A PENDING lock is implemented by
|
|
** obtaining a write-lock on the 'pending byte'. This ensures that no new
|
|
** SHARED locks can be obtained, but existing SHARED locks are allowed to
|
|
** persist. If the call to this function fails to obtain the EXCLUSIVE
|
|
** lock in this case, it holds the PENDING lock instead. The client may
|
|
** then re-attempt the EXCLUSIVE lock later on, after existing SHARED
|
|
** locks have cleared.
|
|
*/
|
|
rc = SQLITE_OK
|
|
pFile = id
|
|
tErrno = 0
|
|
/* If there is already a lock of this type or more restrictive on the
|
|
** unixFile, do nothing. Don't use the end_lock: exit path, as
|
|
** unixEnterMutex() hasn't been called yet.
|
|
*/
|
|
if libc.Int32FromUint8((*TunixFile)(unsafe.Pointer(pFile)).FeFileLock) >= eFileLock {
|
|
return SQLITE_OK
|
|
}
|
|
/* Make sure the locking sequence is correct.
|
|
** (1) We never move from unlocked to anything higher than shared lock.
|
|
** (2) SQLite never explicitly requests a pending lock.
|
|
** (3) A shared lock is always held when a reserve lock is requested.
|
|
*/
|
|
/* This mutex is needed because pFile->pInode is shared across threads
|
|
*/
|
|
pInode = (*TunixFile)(unsafe.Pointer(pFile)).FpInode
|
|
Xsqlite3_mutex_enter(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
|
|
/* If some thread using this PID has a lock via a different unixFile*
|
|
** handle that precludes the requested lock, return BUSY.
|
|
*/
|
|
if libc.Int32FromUint8((*TunixFile)(unsafe.Pointer(pFile)).FeFileLock) != libc.Int32FromUint8((*TunixInodeInfo)(unsafe.Pointer(pInode)).FeFileLock) && (libc.Int32FromUint8((*TunixInodeInfo)(unsafe.Pointer(pInode)).FeFileLock) >= int32(PENDING_LOCK) || eFileLock > int32(SHARED_LOCK)) {
|
|
rc = int32(SQLITE_BUSY)
|
|
goto end_lock
|
|
}
|
|
/* If a SHARED lock is requested, and some thread using this PID already
|
|
** has a SHARED or RESERVED lock, then increment reference counts and
|
|
** return SQLITE_OK.
|
|
*/
|
|
if eFileLock == int32(SHARED_LOCK) && (libc.Int32FromUint8((*TunixInodeInfo)(unsafe.Pointer(pInode)).FeFileLock) == int32(SHARED_LOCK) || libc.Int32FromUint8((*TunixInodeInfo)(unsafe.Pointer(pInode)).FeFileLock) == int32(RESERVED_LOCK)) {
|
|
(*TunixFile)(unsafe.Pointer(pFile)).FeFileLock = uint8(SHARED_LOCK)
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FnShared = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FnShared + 1
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FnLock = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FnLock + 1
|
|
goto end_lock
|
|
}
|
|
/* A PENDING lock is needed before acquiring a SHARED lock and before
|
|
** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
|
|
** be released.
|
|
*/
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_len = int64(1)
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_whence = SEEK_SET
|
|
if eFileLock == int32(SHARED_LOCK) || eFileLock == int32(EXCLUSIVE_LOCK) && libc.Int32FromUint8((*TunixFile)(unsafe.Pointer(pFile)).FeFileLock) == int32(RESERVED_LOCK) {
|
|
if eFileLock == int32(SHARED_LOCK) {
|
|
v1 = int32(F_RDLCK)
|
|
} else {
|
|
v1 = int32(F_WRLCK)
|
|
}
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_type = int16(v1)
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_start = int64(_sqlite3PendingByte)
|
|
if _unixFileLock(tls, pFile, bp) != 0 {
|
|
tErrno = **(**int32)(__ccgo_up(libc.X__errno(tls)))
|
|
rc = _sqliteErrorFromPosixError(tls, tErrno, libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(15)<<libc.Int32FromInt32(8))
|
|
if rc != int32(SQLITE_BUSY) {
|
|
_storeLastErrno(tls, pFile, tErrno)
|
|
}
|
|
goto end_lock
|
|
} else {
|
|
if eFileLock == int32(EXCLUSIVE_LOCK) {
|
|
(*TunixFile)(unsafe.Pointer(pFile)).FeFileLock = uint8(PENDING_LOCK)
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FeFileLock = uint8(PENDING_LOCK)
|
|
}
|
|
}
|
|
}
|
|
/* If control gets to this point, then actually go ahead and make
|
|
** operating system calls for the specified lock.
|
|
*/
|
|
if eFileLock == int32(SHARED_LOCK) {
|
|
/* Now get the read-lock */
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_start = int64(_sqlite3PendingByte + libc.Int32FromInt32(2))
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_len = int64(SHARED_SIZE)
|
|
if _unixFileLock(tls, pFile, bp) != 0 {
|
|
tErrno = **(**int32)(__ccgo_up(libc.X__errno(tls)))
|
|
rc = _sqliteErrorFromPosixError(tls, tErrno, libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(15)<<libc.Int32FromInt32(8))
|
|
}
|
|
/* Drop the temporary PENDING lock */
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_start = int64(_sqlite3PendingByte)
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_len = int64(1)
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_type = int16(F_UNLCK)
|
|
if _unixFileLock(tls, pFile, bp) != 0 && rc == SQLITE_OK {
|
|
/* This could happen with a network mount */
|
|
tErrno = **(**int32)(__ccgo_up(libc.X__errno(tls)))
|
|
rc = libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(8)<<libc.Int32FromInt32(8)
|
|
}
|
|
if rc != 0 {
|
|
if rc != int32(SQLITE_BUSY) {
|
|
_storeLastErrno(tls, pFile, tErrno)
|
|
}
|
|
goto end_lock
|
|
} else {
|
|
(*TunixFile)(unsafe.Pointer(pFile)).FeFileLock = uint8(SHARED_LOCK)
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FnLock = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FnLock + 1
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FnShared = int32(1)
|
|
}
|
|
} else {
|
|
if eFileLock == int32(EXCLUSIVE_LOCK) && (*TunixInodeInfo)(unsafe.Pointer(pInode)).FnShared > int32(1) {
|
|
/* We are trying for an exclusive lock but another thread in this
|
|
** same process is still holding a shared lock. */
|
|
rc = int32(SQLITE_BUSY)
|
|
} else {
|
|
if _unixIsSharingShmNode(tls, pFile) != 0 {
|
|
/* We are in WAL mode and attempting to delete the SHM and WAL
|
|
** files due to closing the connection or changing out of WAL mode,
|
|
** but another process still holds locks on the SHM file, thus
|
|
** indicating that database locks have been broken, perhaps due
|
|
** to a rogue close(open(dbFile)) or similar.
|
|
*/
|
|
rc = int32(SQLITE_BUSY)
|
|
} else {
|
|
/* The request was for a RESERVED or EXCLUSIVE lock. It is
|
|
** assumed that there is a SHARED or greater lock on the file
|
|
** already.
|
|
*/
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_type = int16(F_WRLCK)
|
|
if eFileLock == int32(RESERVED_LOCK) {
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_start = int64(_sqlite3PendingByte + libc.Int32FromInt32(1))
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_len = int64(1)
|
|
} else {
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_start = int64(_sqlite3PendingByte + libc.Int32FromInt32(2))
|
|
(**(**Tflock)(__ccgo_up(bp))).Fl_len = int64(SHARED_SIZE)
|
|
}
|
|
if _unixFileLock(tls, pFile, bp) != 0 {
|
|
tErrno = **(**int32)(__ccgo_up(libc.X__errno(tls)))
|
|
rc = _sqliteErrorFromPosixError(tls, tErrno, libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(15)<<libc.Int32FromInt32(8))
|
|
if rc != int32(SQLITE_BUSY) {
|
|
_storeLastErrno(tls, pFile, tErrno)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
(*TunixFile)(unsafe.Pointer(pFile)).FeFileLock = libc.Uint8FromInt32(eFileLock)
|
|
(*TunixInodeInfo)(unsafe.Pointer(pInode)).FeFileLock = libc.Uint8FromInt32(eFileLock)
|
|
}
|
|
goto end_lock
|
|
end_lock:
|
|
;
|
|
Xsqlite3_mutex_leave(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read data from a file into a buffer. Return SQLITE_OK if all
|
|
// ** bytes were read successfully and SQLITE_IOERR if anything goes
|
|
// ** wrong.
|
|
// */
|
|
func _unixRead(tls *libc.TLS, id uintptr, pBuf uintptr, amt int32, offset Tsqlite3_int64) (r int32) {
|
|
var got int32
|
|
var pFile uintptr
|
|
_, _ = got, pFile
|
|
pFile = id
|
|
/* 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. */
|
|
got = _seekAndRead(tls, pFile, offset, pBuf, amt)
|
|
if got == amt {
|
|
return SQLITE_OK
|
|
} else {
|
|
if got < 0 {
|
|
/* pFile->lastErrno has been set by seekAndRead().
|
|
** Usually we return SQLITE_IOERR_READ here, though for some
|
|
** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The
|
|
** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT
|
|
** prior to returning to the application by the sqlite3ApiExit()
|
|
** routine.
|
|
*/
|
|
switch (*TunixFile)(unsafe.Pointer(pFile)).FlastErrno {
|
|
case int32(ERANGE):
|
|
fallthrough
|
|
case int32(EIO):
|
|
fallthrough
|
|
case int32(ENXIO):
|
|
return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(33)<<libc.Int32FromInt32(8)
|
|
}
|
|
return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
} else {
|
|
_storeLastErrno(tls, pFile, 0) /* not a system error */
|
|
/* Unread parts of the buffer must be zero-filled */
|
|
libc.Xmemset(tls, pBuf+uintptr(got), 0, libc.Uint64FromInt32(amt-got))
|
|
return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(2)<<libc.Int32FromInt32(8)
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the third argument is non-NULL, then this function releases a
|
|
// ** reference obtained by an earlier call to unixFetch(). The second
|
|
// ** argument passed to this function must be the same as the corresponding
|
|
// ** argument that was passed to the unixFetch() invocation.
|
|
// **
|
|
// ** Or, if the third argument is NULL, then this function is being called
|
|
// ** to inform the VFS layer that, according to POSIX, any existing mapping
|
|
// ** may now be invalid and should be unmapped.
|
|
// */
|
|
func _unixUnfetch(tls *libc.TLS, fd uintptr, iOff Ti64, p uintptr) (r int32) {
|
|
_ = fd
|
|
_ = p
|
|
_ = iOff
|
|
return SQLITE_OK
|
|
}
|
|
|
|
/*
|
|
** Here ends the implementation of all sqlite3_file methods.
|
|
**
|
|
********************** End sqlite3_file Methods *******************************
|
|
******************************************************************************/
|
|
|
|
/*
|
|
** This division contains definitions of sqlite3_io_methods objects that
|
|
** implement various file locking strategies. It also contains definitions
|
|
** of "finder" functions. A finder-function is used to locate the appropriate
|
|
** sqlite3_io_methods object for a particular database file. The pAppData
|
|
** field of the sqlite3_vfs VFS objects are initialized to be pointers to
|
|
** the correct finder-function for that VFS.
|
|
**
|
|
** Most finder functions return a pointer to a fixed sqlite3_io_methods
|
|
** object. The only interesting finder-function is autolockIoFinder, which
|
|
** looks at the filesystem type and tries to guess the best locking
|
|
** strategy from that.
|
|
**
|
|
** For finder-function F, two objects are created:
|
|
**
|
|
** (1) The real finder-function named "FImpt()".
|
|
**
|
|
** (2) A constant pointer to this function named just "F".
|
|
**
|
|
**
|
|
** A pointer to the F pointer is used as the pAppData value for VFS
|
|
** objects. We have to do this instead of letting pAppData point
|
|
** directly at the finder-function since C90 rules prevent a void*
|
|
** from be cast into a function pointer.
|
|
**
|
|
**
|
|
** Each instance of this macro generates two objects:
|
|
**
|
|
** * A constant sqlite3_io_methods object call METHOD that has locking
|
|
** methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
|
|
**
|
|
** * An I/O method finder function called FINDER that returns a pointer
|
|
** to the METHOD object in the previous bullet.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Write the current contents of in-memory linked-list pList to a level-0
|
|
// ** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if
|
|
// ** successful, or an SQLite error code otherwise.
|
|
// **
|
|
// ** The format of a PMA is:
|
|
// **
|
|
// ** * A varint. This varint contains the total number of bytes of content
|
|
// ** in the PMA (not including the varint itself).
|
|
// **
|
|
// ** * One or more records packed end-to-end in order of ascending keys.
|
|
// ** Each record consists of a varint followed by a blob of data (the
|
|
// ** key). The varint is the number of bytes in the blob of data.
|
|
// */
|
|
func _vdbeSorterListToPMA(tls *libc.TLS, pTask uintptr, pList uintptr) (r int32) {
|
|
bp := tls.Alloc(64)
|
|
defer tls.Free(64)
|
|
var db, p, pNext uintptr
|
|
var rc int32
|
|
var _ /* writer at bp+0 */ TPmaWriter
|
|
_, _, _, _ = db, p, pNext, rc
|
|
db = (*TVdbeSorter)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask)).FpSorter)).Fdb
|
|
rc = SQLITE_OK /* Object used to write to the file */
|
|
libc.Xmemset(tls, bp, 0, uint64(56))
|
|
/* If the first temporary PMA file has not been opened, open it now. */
|
|
if (*TSortSubtask)(unsafe.Pointer(pTask)).Ffile.FpFd == uintptr(0) {
|
|
rc = _vdbeSorterOpenTempFile(tls, db, 0, pTask+64)
|
|
}
|
|
/* Try to get the file to memory map */
|
|
if rc == SQLITE_OK {
|
|
}
|
|
/* Sort the list */
|
|
if rc == SQLITE_OK {
|
|
rc = _vdbeSorterSort(tls, pTask, pList)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
pNext = uintptr(0)
|
|
_vdbePmaWriterInit(tls, (*TSortSubtask)(unsafe.Pointer(pTask)).Ffile.FpFd, bp, (*TVdbeSorter)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask)).FpSorter)).Fpgsz, (*TSortSubtask)(unsafe.Pointer(pTask)).Ffile.FiEof)
|
|
(*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA = (*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA + 1
|
|
_vdbePmaWriteVarint(tls, bp, libc.Uint64FromInt64((*TSorterList)(unsafe.Pointer(pList)).FszPMA))
|
|
p = (*TSorterList)(unsafe.Pointer(pList)).FpList
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
pNext = *(*uintptr)(unsafe.Pointer(p + 8))
|
|
_vdbePmaWriteVarint(tls, bp, libc.Uint64FromInt32((*TSorterRecord)(unsafe.Pointer(p)).FnVal))
|
|
_vdbePmaWriteBlob(tls, bp, p+libc.UintptrFromInt32(1)*16, (*TSorterRecord)(unsafe.Pointer(p)).FnVal)
|
|
if (*TSorterList)(unsafe.Pointer(pList)).FaMemory == uintptr(0) {
|
|
Xsqlite3_free(tls, p)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = pNext
|
|
}
|
|
(*TSorterList)(unsafe.Pointer(pList)).FpList = p
|
|
rc = _vdbePmaWriterFinish(tls, bp, pTask+64+8, pTask+96)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
type cpuid_t = Tcpuid_t
|
|
|
|
const fd_mask = 0
|
|
|
|
type max_align_t = Tmax_align_t
|
|
|
|
/*
|
|
** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
|
|
** This allows better measurements of where memcpy() is used when running
|
|
** cachegrind. But this macro version of memcpy() is very slow so it
|
|
** should not be used in production. This is a performance measurement
|
|
** hack only.
|
|
*/
|
|
|
|
/*
|
|
** If compiling for a processor that lacks floating point support,
|
|
** substitute integer for floating-point
|
|
*/
|
|
|
|
/*
|
|
** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0
|
|
** afterward. Having this macro allows us to cause the C compiler
|
|
** to omit code used by TEMP tables without messy #ifndef statements.
|
|
*/
|
|
|
|
/*
|
|
** The "file format" number is an integer that is incremented whenever
|
|
** the VDBE-level file format changes. The following macros define the
|
|
** the default file format for new databases and the maximum file format
|
|
** that the library can read.
|
|
*/
|
|
|
|
/*
|
|
** Determine whether triggers are recursive by default. This can be
|
|
** changed at run-time using a pragma.
|
|
*/
|
|
|
|
/*
|
|
** Provide a default value for SQLITE_TEMP_STORE in case it is not specified
|
|
** on the command-line
|
|
*/
|
|
|
|
/*
|
|
** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
|
|
** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
|
|
** to zero.
|
|
*/
|
|
|
|
/*
|
|
** The default initial allocation for the pagecache when using separate
|
|
** pagecaches for each database connection. A positive number is the
|
|
** number of pages. A negative number N translations means that a buffer
|
|
** of -1024*N bytes is allocated and used for as many pages as it will hold.
|
|
**
|
|
** The default value of "20" was chosen to minimize the run-time of the
|
|
** speedtest1 test program with options: --shrink-memory --reprepare
|
|
*/
|
|
|
|
/*
|
|
** Default value for the SQLITE_CONFIG_SORTERREF_SIZE option.
|
|
*/
|
|
|
|
/*
|
|
** The compile-time options SQLITE_MMAP_READWRITE and
|
|
** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another.
|
|
** You must choose one or the other (or neither) but not both.
|
|
*/
|
|
|
|
/*
|
|
** GCC does not define the offsetof() macro so we'll have to do it
|
|
** ourselves.
|
|
*/
|
|
|
|
/*
|
|
** sizeof64() is like sizeof(), but always returns a 64-bit value, even
|
|
** on 32-bit builds. This can help to avoid overflow by ensuring 64-bit
|
|
** arithmetic is used consistently in both 32-bit and 64-bit builds.
|
|
*/
|
|
|
|
/*
|
|
** Work around C99 "flex-array" syntax for pre-C99 compilers, so as
|
|
** to avoid complaints from -fsanitize=strict-bounds.
|
|
*/
|
|
|
|
/*
|
|
** Macros to compute minimum and maximum of two numbers.
|
|
*/
|
|
|
|
/*
|
|
** Swap two objects of type TYPE.
|
|
*/
|
|
|
|
/*
|
|
** Check to see if this machine uses EBCDIC. (Yes, believe it or
|
|
** not, there are still machines out there that use EBCDIC.)
|
|
*/
|
|
|
|
type qdiv_t = Tqdiv_t
|
|
|
|
type t__in_addr_t = uint32
|
|
|
|
type t__in_port_t = uint16
|
|
|
|
type t__mode_t = uint32
|
|
|
|
type t__wctrans_t = uintptr
|
|
|
|
type t__wctype_t = uintptr
|
|
|
|
type unchar = Tunchar
|