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>
8437 lines
336 KiB
Go
8437 lines
336 KiB
Go
// Code generated by modernc.org/undup from the per-target sqlite_*.go files; DO NOT EDIT.
|
|
|
|
//go:build (freebsd && arm64) || (linux && arm64) || (linux && ppc64le) || (linux && riscv64) || (linux && s390x) || (openbsd && arm64)
|
|
|
|
package sqlite3
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"modernc.org/libc"
|
|
)
|
|
|
|
type TColumn = struct {
|
|
FzCnName uintptr
|
|
F__ccgo8 uint8
|
|
Faffinity uint8
|
|
FszEst Tu8
|
|
FhName Tu8
|
|
FiDflt Tu16
|
|
FcolFlags Tu16
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** A structure for holding a single date and time.
|
|
// */
|
|
type TDateTime = struct {
|
|
FiJD Tsqlite3_int64
|
|
FY int32
|
|
FM int32
|
|
FD int32
|
|
Fh int32
|
|
Fm int32
|
|
Ftz int32
|
|
Fs float64
|
|
FvalidJD uint8
|
|
FvalidYMD uint8
|
|
FvalidHMS uint8
|
|
FnFloor uint8
|
|
F__ccgo44 uint8
|
|
}
|
|
|
|
type TExpr = struct {
|
|
Fop Tu8
|
|
FaffExpr uint8
|
|
Fop2 Tu8
|
|
Fflags Tu32
|
|
Fu struct {
|
|
FiValue [0]int32
|
|
FzToken uintptr
|
|
}
|
|
FpLeft uintptr
|
|
FpRight uintptr
|
|
Fx struct {
|
|
FpSelect [0]uintptr
|
|
FpList uintptr
|
|
}
|
|
FnHeight int32
|
|
FiTable int32
|
|
FiColumn TynVar
|
|
FiAgg Ti16
|
|
Fw struct {
|
|
FiOfst [0]int32
|
|
FiJoin int32
|
|
}
|
|
FpAggInfo uintptr
|
|
Fy struct {
|
|
FpWin [0]uintptr
|
|
FnReg [0]int32
|
|
Fsub [0]struct {
|
|
FiAddr int32
|
|
FregReturn int32
|
|
}
|
|
FpTab uintptr
|
|
}
|
|
}
|
|
|
|
type TJsonString = struct {
|
|
FpCtx uintptr
|
|
FzBuf uintptr
|
|
FnAlloc Tu64
|
|
FnUsed Tu64
|
|
FbStatic Tu8
|
|
FeErr Tu8
|
|
FzSpace [100]uint8
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Each open file is managed by a separate instance of the "Pager" structure.
|
|
// */
|
|
type TPager = struct {
|
|
FpVfs uintptr
|
|
FexclusiveMode Tu8
|
|
FjournalMode Tu8
|
|
FuseJournal Tu8
|
|
FnoSync Tu8
|
|
FfullSync Tu8
|
|
FextraSync Tu8
|
|
FsyncFlags Tu8
|
|
FwalSyncFlags Tu8
|
|
FtempFile Tu8
|
|
FnoLock Tu8
|
|
FreadOnly Tu8
|
|
FmemDb Tu8
|
|
FmemVfs Tu8
|
|
FeState Tu8
|
|
FeLock Tu8
|
|
FchangeCountDone Tu8
|
|
FsetSuper Tu8
|
|
FdoNotSpill Tu8
|
|
FsubjInMemory Tu8
|
|
FbUseFetch Tu8
|
|
FhasHeldSharedLock Tu8
|
|
FdbSize TPgno
|
|
FdbOrigSize TPgno
|
|
FdbFileSize TPgno
|
|
FdbHintSize TPgno
|
|
FerrCode int32
|
|
FnRec int32
|
|
FcksumInit Tu32
|
|
FnSubRec Tu32
|
|
FpInJournal uintptr
|
|
Ffd uintptr
|
|
Fjfd uintptr
|
|
Fsjfd uintptr
|
|
FjournalOff Ti64
|
|
FjournalHdr Ti64
|
|
FpBackup uintptr
|
|
FaSavepoint uintptr
|
|
FnSavepoint int32
|
|
FiDataVersion Tu32
|
|
FdbFileVers [16]uint8
|
|
FnMmapOut int32
|
|
FszMmap Tsqlite3_int64
|
|
FpMmapFreelist uintptr
|
|
FnExtra Tu16
|
|
FnReserve Ti16
|
|
FvfsFlags Tu32
|
|
FsectorSize Tu32
|
|
FmxPgno TPgno
|
|
FlckPgno TPgno
|
|
FpageSize Ti64
|
|
FjournalSizeLimit Ti64
|
|
FzFilename uintptr
|
|
FzJournal uintptr
|
|
FxBusyHandler uintptr
|
|
FpBusyHandlerArg uintptr
|
|
FaStat [4]Tu32
|
|
FxReiniter uintptr
|
|
FxGet uintptr
|
|
FpTmpSpace uintptr
|
|
FpPCache uintptr
|
|
FpWal uintptr
|
|
FzWal uintptr
|
|
}
|
|
|
|
type Tsqlite3rbu = struct {
|
|
FeStage int32
|
|
FdbMain uintptr
|
|
FdbRbu uintptr
|
|
FzTarget uintptr
|
|
FzRbu uintptr
|
|
FzState uintptr
|
|
FzStateDb [5]uint8
|
|
Frc int32
|
|
FzErrmsg uintptr
|
|
FnStep int32
|
|
FnProgress Tsqlite3_int64
|
|
Fobjiter TRbuObjIter
|
|
FzVfsName uintptr
|
|
FpTargetFd uintptr
|
|
FnPagePerSector int32
|
|
FiOalSz Ti64
|
|
FnPhaseOneStep Ti64
|
|
FpRenameArg uintptr
|
|
FxRename uintptr
|
|
FiMaxFrame Tu32
|
|
FmLock Tu32
|
|
FnFrame int32
|
|
FnFrameAlloc int32
|
|
FaFrame uintptr
|
|
Fpgsz int32
|
|
FaBuf uintptr
|
|
FiWalCksum Ti64
|
|
FszTemp Ti64
|
|
FszTempLimit Ti64
|
|
FnRbu int32
|
|
FpRbuFd uintptr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate memory to hold names for a database, journal file, WAL file,
|
|
// ** and query parameters. The pointer returned is valid for use by
|
|
// ** sqlite3_filename_database() and sqlite3_uri_parameter() and related
|
|
// ** functions.
|
|
// **
|
|
// ** Memory layout must be compatible with that generated by the pager
|
|
// ** and expected by sqlite3_uri_parameter() and databaseName().
|
|
// */
|
|
func Xsqlite3_create_filename(tls *libc.TLS, zDatabase uintptr, zJournal uintptr, zWal uintptr, nParam int32, azParam uintptr) (r uintptr) {
|
|
var i int32
|
|
var nByte Tsqlite3_int64
|
|
var p, pResult, v2 uintptr
|
|
_, _, _, _, _ = i, nByte, p, pResult, v2
|
|
nByte = libc.Int64FromUint64(libc.Xstrlen(tls, zDatabase) + libc.Xstrlen(tls, zJournal) + libc.Xstrlen(tls, zWal) + uint64(10))
|
|
i = 0
|
|
for {
|
|
if !(i < nParam*int32(2)) {
|
|
break
|
|
}
|
|
nByte = libc.Int64FromUint64(uint64(nByte) + uint64(libc.Xstrlen(tls, **(**uintptr)(__ccgo_up(azParam + uintptr(i)*8)))+libc.Uint64FromInt32(1)))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
v2 = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(nByte))
|
|
p = v2
|
|
pResult = v2
|
|
if p == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
libc.Xmemset(tls, p, 0, uint64(4))
|
|
p = p + uintptr(4)
|
|
p = _appendText(tls, p, zDatabase)
|
|
i = 0
|
|
for {
|
|
if !(i < nParam*int32(2)) {
|
|
break
|
|
}
|
|
p = _appendText(tls, p, **(**uintptr)(__ccgo_up(azParam + uintptr(i)*8)))
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
v2 = p
|
|
p = p + 1
|
|
**(**uint8)(__ccgo_up(v2)) = uint8(0)
|
|
p = _appendText(tls, p, zJournal)
|
|
p = _appendText(tls, p, zWal)
|
|
v2 = p
|
|
p = p + 1
|
|
**(**uint8)(__ccgo_up(v2)) = uint8(0)
|
|
v2 = p
|
|
p = p + 1
|
|
**(**uint8)(__ccgo_up(v2)) = uint8(0)
|
|
return pResult + uintptr(4)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the sqlite3_file for the main database given the name
|
|
// ** of the corresponding WAL or Journal name as passed into
|
|
// ** xOpen.
|
|
// */
|
|
func Xsqlite3_database_file_object(tls *libc.TLS, zName uintptr) (r uintptr) {
|
|
var p, pPager uintptr
|
|
_, _ = p, pPager
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(zName + uintptr(-libc.Int32FromInt32(1))))) != 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zName + uintptr(-libc.Int32FromInt32(2))))) != 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zName + uintptr(-libc.Int32FromInt32(3))))) != 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zName + uintptr(-libc.Int32FromInt32(4))))) != 0 {
|
|
zName = zName - 1
|
|
}
|
|
p = zName - uintptr(4) - uintptr(8)
|
|
pPager = **(**uintptr)(__ccgo_up(p))
|
|
return (*TPager)(unsafe.Pointer(pPager)).Ffd
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called from within a pre-update callback to retrieve
|
|
// ** a field of the row currently being updated or deleted.
|
|
// */
|
|
func Xsqlite3_preupdate_old(tls *libc.TLS, db uintptr, iIdx int32, ppValue uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var aRec, p, pCol, pDflt, pMem, v1 uintptr
|
|
var iStore, nByte, rc int32
|
|
var nRec Tu32
|
|
var _ /* pVal at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _ = aRec, iStore, nByte, nRec, p, pCol, pDflt, pMem, rc, v1
|
|
rc = SQLITE_OK
|
|
iStore = 0
|
|
p = (*Tsqlite3)(unsafe.Pointer(db)).FpPreUpdate
|
|
/* Test that this call is being made from within an SQLITE_DELETE or
|
|
** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
|
|
if !(p != 0) || (*TPreUpdate)(unsafe.Pointer(p)).Fop == int32(SQLITE_INSERT) {
|
|
rc = _sqlite3MisuseError(tls, int32(95913))
|
|
goto preupdate_old_out
|
|
}
|
|
if (*TPreUpdate)(unsafe.Pointer(p)).FpPk != 0 {
|
|
iStore = _sqlite3TableColumnToIndex(tls, (*TPreUpdate)(unsafe.Pointer(p)).FpPk, iIdx)
|
|
} else {
|
|
if iIdx >= int32((*TTable)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab)).FnCol) {
|
|
rc = _sqlite3MisuseError(tls, int32(95919))
|
|
goto preupdate_old_out
|
|
} else {
|
|
iStore = int32(_sqlite3TableColumnToStorage(tls, (*TPreUpdate)(unsafe.Pointer(p)).FpTab, int16(iIdx)))
|
|
}
|
|
}
|
|
if iStore >= int32((*TVdbeCursor)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpCsr)).FnField) || iStore < 0 {
|
|
rc = int32(SQLITE_RANGE)
|
|
goto preupdate_old_out
|
|
}
|
|
if iIdx == int32((*TTable)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab)).FiPKey) {
|
|
v1 = p + 80
|
|
pMem = v1
|
|
**(**uintptr)(__ccgo_up(ppValue)) = v1
|
|
_sqlite3VdbeMemSetInt64(tls, pMem, (*TPreUpdate)(unsafe.Pointer(p)).FiKey1)
|
|
} else {
|
|
/* If the old.* record has not yet been loaded into memory, do so now. */
|
|
if (*TPreUpdate)(unsafe.Pointer(p)).FpUnpacked == uintptr(0) {
|
|
nRec = _sqlite3BtreePayloadSize(tls, *(*uintptr)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpCsr + 48)))
|
|
aRec = _sqlite3DbMallocRaw(tls, db, uint64(nRec))
|
|
if !(aRec != 0) {
|
|
goto preupdate_old_out
|
|
}
|
|
rc = _sqlite3BtreePayload(tls, *(*uintptr)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpCsr + 48)), uint32(0), nRec, aRec)
|
|
if rc == SQLITE_OK {
|
|
(*TPreUpdate)(unsafe.Pointer(p)).FpUnpacked = _vdbeUnpackRecord(tls, (*TPreUpdate)(unsafe.Pointer(p)).FpKeyinfo, libc.Int32FromUint32(nRec), aRec)
|
|
if !((*TPreUpdate)(unsafe.Pointer(p)).FpUnpacked != 0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
if rc != SQLITE_OK {
|
|
_sqlite3DbFree(tls, db, aRec)
|
|
goto preupdate_old_out
|
|
}
|
|
(*TPreUpdate)(unsafe.Pointer(p)).FaRecord = aRec
|
|
}
|
|
v1 = (*TUnpackedRecord)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpUnpacked)).FaMem + uintptr(iStore)*56
|
|
**(**uintptr)(__ccgo_up(ppValue)) = v1
|
|
pMem = v1
|
|
if iStore >= libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpUnpacked)).FnField) {
|
|
/* This occurs when the table has been extended using ALTER TABLE
|
|
** ADD COLUMN. The value to return is the default value of the column. */
|
|
pCol = (*TTable)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab)).FaCol + uintptr(iIdx)*16
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt) > 0 {
|
|
if (*TPreUpdate)(unsafe.Pointer(p)).FapDflt == uintptr(0) {
|
|
nByte = libc.Int32FromUint64(uint64(8) * libc.Uint64FromInt16((*TTable)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab)).FnCol))
|
|
(*TPreUpdate)(unsafe.Pointer(p)).FapDflt = _sqlite3DbMallocZero(tls, db, libc.Uint64FromInt32(nByte))
|
|
if (*TPreUpdate)(unsafe.Pointer(p)).FapDflt == uintptr(0) {
|
|
goto preupdate_old_out
|
|
}
|
|
}
|
|
if **(**uintptr)(__ccgo_up((*TPreUpdate)(unsafe.Pointer(p)).FapDflt + uintptr(iIdx)*8)) == uintptr(0) {
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
pDflt = (*(*TExprList_item)(unsafe.Pointer((*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab + 64))).FpDfltList + 8 + uintptr(libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt)-int32(1))*32))).FpExpr
|
|
rc = _sqlite3ValueFromExpr(tls, db, pDflt, (*Tsqlite3)(unsafe.Pointer(db)).Fenc, (*TColumn)(unsafe.Pointer(pCol)).Faffinity, bp)
|
|
if rc == SQLITE_OK && **(**uintptr)(__ccgo_up(bp)) == uintptr(0) {
|
|
rc = _sqlite3CorruptError(tls, int32(95975))
|
|
}
|
|
**(**uintptr)(__ccgo_up((*TPreUpdate)(unsafe.Pointer(p)).FapDflt + uintptr(iIdx)*8)) = **(**uintptr)(__ccgo_up(bp))
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppValue)) = **(**uintptr)(__ccgo_up((*TPreUpdate)(unsafe.Pointer(p)).FapDflt + uintptr(iIdx)*8))
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(ppValue)) = _columnNullValue(tls)
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab)).FaCol + uintptr(iIdx)*16))).Faffinity) == int32(SQLITE_AFF_REAL) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
_sqlite3VdbeMemRealify(tls, pMem)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto preupdate_old_out
|
|
preupdate_old_out:
|
|
;
|
|
_sqlite3Error(tls, db, rc)
|
|
return _sqlite3ApiExit(tls, db, rc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append N copies of character c to the given string buffer.
|
|
// */
|
|
func Xsqlite3_str_appendchar(tls *libc.TLS, p uintptr, N int32, c uint8) {
|
|
var v1 int32
|
|
var v2 bool
|
|
var v4 Tu32
|
|
var v5 uintptr
|
|
_, _, _, _ = v1, v2, v4, v5
|
|
if v2 = libc.Int64FromUint32((*Tsqlite3_str)(unsafe.Pointer(p)).FnChar)+int64(N) >= libc.Int64FromUint32((*Tsqlite3_str)(unsafe.Pointer(p)).FnAlloc); v2 {
|
|
v1 = _sqlite3StrAccumEnlarge(tls, p, int64(N))
|
|
N = v1
|
|
}
|
|
if v2 && v1 <= 0 {
|
|
return
|
|
}
|
|
for {
|
|
v1 = N
|
|
N = N - 1
|
|
if !(v1 > 0) {
|
|
break
|
|
}
|
|
v5 = p + 24
|
|
v4 = *(*Tu32)(unsafe.Pointer(v5))
|
|
*(*Tu32)(unsafe.Pointer(v5)) = *(*Tu32)(unsafe.Pointer(v5)) + 1
|
|
**(**uint8)(__ccgo_up((*Tsqlite3_str)(unsafe.Pointer(p)).FzText + uintptr(v4))) = c
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Print into memory obtained from sqlite3_malloc(). Omit the internal
|
|
// ** %-conversion extensions.
|
|
// */
|
|
func Xsqlite3_vmprintf(tls *libc.TLS, zFormat uintptr, ap Tva_list) (r uintptr) {
|
|
bp := tls.Alloc(112)
|
|
defer tls.Free(112)
|
|
var z uintptr
|
|
var _ /* acc at bp+72 */ TStrAccum
|
|
var _ /* zBase at bp+0 */ [70]uint8
|
|
_ = z
|
|
if Xsqlite3_initialize(tls) != 0 {
|
|
return uintptr(0)
|
|
}
|
|
_sqlite3StrAccumInit(tls, bp+72, uintptr(0), bp, int32(70), int32(SQLITE_MAX_LENGTH))
|
|
Xsqlite3_str_vappendf(tls, bp+72, zFormat, ap)
|
|
z = _sqlite3StrAccumFinish(tls, bp+72)
|
|
return z
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Processing is determine by the affinity parameter:
|
|
// **
|
|
// ** SQLITE_AFF_INTEGER:
|
|
// ** SQLITE_AFF_REAL:
|
|
// ** SQLITE_AFF_NUMERIC:
|
|
// ** Try to convert pRec to an integer representation or a
|
|
// ** floating-point representation if an integer representation
|
|
// ** is not possible. Note that the integer representation is
|
|
// ** always preferred, even if the affinity is REAL, because
|
|
// ** an integer representation is more space efficient on disk.
|
|
// **
|
|
// ** SQLITE_AFF_FLEXNUM:
|
|
// ** If the value is text, then try to convert it into a number of
|
|
// ** some kind (integer or real) but do not make any other changes.
|
|
// **
|
|
// ** SQLITE_AFF_TEXT:
|
|
// ** Convert pRec to a text representation.
|
|
// **
|
|
// ** SQLITE_AFF_BLOB:
|
|
// ** SQLITE_AFF_NONE:
|
|
// ** No-op. pRec is unchanged.
|
|
// */
|
|
func _applyAffinity(tls *libc.TLS, pRec uintptr, affinity uint8, enc Tu8) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint8(affinity) >= int32(SQLITE_AFF_NUMERIC) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRec)).Fflags)&int32(MEM_Int) == 0 { /*OPTIMIZATION-IF-FALSE*/
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRec)).Fflags)&(libc.Int32FromInt32(MEM_Real)|libc.Int32FromInt32(MEM_IntReal)) == 0 {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRec)).Fflags)&int32(MEM_Str) != 0 {
|
|
_applyNumericAffinity(tls, pRec, int32(1))
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8(affinity) <= int32(SQLITE_AFF_REAL) {
|
|
_sqlite3VdbeIntegerAffinity(tls, pRec)
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8(affinity) == int32(SQLITE_AFF_TEXT) {
|
|
/* Only attempt the conversion to TEXT if there is an integer or real
|
|
** representation (blob and NULL do not get converted) but no string
|
|
** representation. It would be harmless to repeat the conversion if
|
|
** there is already a string rep, but it is pointless to waste those
|
|
** CPU cycles. */
|
|
if 0 == libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRec)).Fflags)&int32(MEM_Str) { /*OPTIMIZATION-IF-FALSE*/
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRec)).Fflags)&(libc.Int32FromInt32(MEM_Real)|libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
_sqlite3VdbeMemStringify(tls, pRec, enc, uint8(1))
|
|
}
|
|
}
|
|
v1 = pRec + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(MEM_Real) | libc.Int32FromInt32(MEM_Int) | libc.Int32FromInt32(MEM_IntReal)))
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will evaluate all == and IN constraints for an
|
|
// ** index scan.
|
|
// **
|
|
// ** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c).
|
|
// ** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10
|
|
// ** The index has as many as three equality constraints, but in this
|
|
// ** example, the third "c" value is an inequality. So only two
|
|
// ** constraints are coded. This routine will generate code to evaluate
|
|
// ** a==5 and b IN (1,2,3). The current values for a and b will be stored
|
|
// ** in consecutive registers and the index of the first register is returned.
|
|
// **
|
|
// ** In the example above nEq==2. But this subroutine works for any value
|
|
// ** of nEq including 0. If nEq==0, this routine is nearly a no-op.
|
|
// ** The only thing it does is allocate the pLevel->iMem memory cell and
|
|
// ** compute the affinity string.
|
|
// **
|
|
// ** The nExtraReg parameter is 0 or 1. It is 0 if all WHERE clause constraints
|
|
// ** are == or IN and are covered by the nEq. nExtraReg is 1 if there is
|
|
// ** an inequality constraint (such as the "c>=5 AND c<10" in the example) that
|
|
// ** occurs after the nEq quality constraints.
|
|
// **
|
|
// ** This routine allocates a range of nEq+nExtraReg memory cells and returns
|
|
// ** the index of the first memory cell in that range. The code that
|
|
// ** calls this routine will use that memory range to store keys for
|
|
// ** start and termination conditions of the loop.
|
|
// ** key value of the loop. If one or more IN operators appear, then
|
|
// ** this routine allocates an additional nEq memory cells for internal
|
|
// ** use.
|
|
// **
|
|
// ** Before returning, *pzAff is set to point to a buffer containing a
|
|
// ** copy of the column affinity string of the index allocated using
|
|
// ** sqlite3DbMalloc(). Except, entries in the copy of the string associated
|
|
// ** with equality constraints that use BLOB or NONE affinity are set to
|
|
// ** SQLITE_AFF_BLOB. This is to deal with SQL such as the following:
|
|
// **
|
|
// ** CREATE TABLE t1(a TEXT PRIMARY KEY, b);
|
|
// ** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b;
|
|
// **
|
|
// ** In the example above, the index on t1(a) has TEXT affinity. But since
|
|
// ** the right hand side of the equality constraint (t2.b) has BLOB/NONE affinity,
|
|
// ** no conversion should be attempted before using a t2.b value as part of
|
|
// ** a key to search the index. Hence the first byte in the returned affinity
|
|
// ** string in this example would be set to SQLITE_AFF_BLOB.
|
|
// */
|
|
func _codeAllEqualityTerms(tls *libc.TLS, pParse uintptr, pLevel uintptr, bRev int32, nExtraReg int32, pzAff uintptr) (r int32) {
|
|
var iIdxCur, j, nReg, r1, regBase, v1 int32
|
|
var nEq, nSkip Tu16
|
|
var pIdx, pLoop, pRight, pTerm, v, zAff uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _ = iIdxCur, j, nEq, nReg, nSkip, pIdx, pLoop, pRight, pTerm, r1, regBase, v, zAff, v1 /* Number of left-most columns to skip */
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe /* Affinity string to return */
|
|
/* This module is only called on query plans that use an index. */
|
|
pLoop = (*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop
|
|
nEq = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq
|
|
nSkip = (*TWhereLoop)(unsafe.Pointer(pLoop)).FnSkip
|
|
pIdx = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex
|
|
/* Figure out how many memory cells we will need then allocate them.
|
|
*/
|
|
regBase = (*TParse)(unsafe.Pointer(pParse)).FnMem + int32(1)
|
|
nReg = libc.Int32FromUint16(nEq) + nExtraReg
|
|
**(**int32)(__ccgo_up(pParse + 60)) += nReg
|
|
zAff = _sqlite3DbStrDup(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, _sqlite3IndexAffinityStr(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pIdx))
|
|
if nSkip != 0 {
|
|
iIdxCur = (*TWhereLevel)(unsafe.Pointer(pLevel)).FiIdxCur
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Null), 0, regBase, regBase+libc.Int32FromUint16(nSkip)-int32(1))
|
|
if bRev != 0 {
|
|
v1 = int32(OP_Last)
|
|
} else {
|
|
v1 = int32(OP_Rewind)
|
|
}
|
|
_sqlite3VdbeAddOp1(tls, v, v1, iIdxCur)
|
|
j = _sqlite3VdbeAddOp0(tls, v, int32(OP_Goto))
|
|
if bRev != 0 {
|
|
v1 = int32(OP_SeekLT)
|
|
} else {
|
|
v1 = int32(OP_SeekGT)
|
|
}
|
|
(*TWhereLevel)(unsafe.Pointer(pLevel)).FaddrSkip = _sqlite3VdbeAddOp4Int(tls, v, v1, iIdxCur, 0, regBase, libc.Int32FromUint16(nSkip))
|
|
_sqlite3VdbeJumpHere(tls, v, j)
|
|
j = 0
|
|
for {
|
|
if !(j < libc.Int32FromUint16(nSkip)) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), iIdxCur, j, regBase+j)
|
|
goto _3
|
|
_3:
|
|
;
|
|
j = j + 1
|
|
}
|
|
}
|
|
/* Evaluate the equality constraints
|
|
*/
|
|
j = libc.Int32FromUint16(nSkip)
|
|
for {
|
|
if !(j < libc.Int32FromUint16(nEq)) {
|
|
break
|
|
}
|
|
pTerm = **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(j)*8))
|
|
/* The following testcase is true for indices with redundant columns.
|
|
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
|
r1 = _codeEqualityTerm(tls, pParse, pTerm, pLevel, j, bRev, regBase+j)
|
|
if r1 != regBase+j {
|
|
if nReg == int32(1) {
|
|
_sqlite3ReleaseTempReg(tls, pParse, regBase)
|
|
regBase = r1
|
|
} else {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Copy), r1, regBase+j)
|
|
}
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&int32(WO_IN) != 0 {
|
|
if (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).Fflags&uint32(EP_xIsSelect) != 0 {
|
|
/* No affinity ever needs to be (or should be) applied to a value
|
|
** from the RHS of an "? IN (SELECT ...)" expression. The
|
|
** sqlite3FindInIndex() routine has already ensured that the
|
|
** affinity of the comparison has been applied to the value. */
|
|
if zAff != 0 {
|
|
**(**uint8)(__ccgo_up(zAff + uintptr(j))) = uint8(SQLITE_AFF_BLOB)
|
|
}
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&int32(WO_ISNULL) == 0 {
|
|
pRight = (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).FpRight
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_IS) == 0 && _sqlite3ExprCanBeNull(tls, pRight) != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IsNull), regBase+j, (*TWhereLevel)(unsafe.Pointer(pLevel)).FaddrBrk)
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr == 0 {
|
|
if libc.Int32FromUint8(_sqlite3CompareAffinity(tls, pRight, **(**uint8)(__ccgo_up(zAff + uintptr(j))))) == int32(SQLITE_AFF_BLOB) {
|
|
**(**uint8)(__ccgo_up(zAff + uintptr(j))) = uint8(SQLITE_AFF_BLOB)
|
|
}
|
|
if _sqlite3ExprNeedsNoAffinityChange(tls, pRight, **(**uint8)(__ccgo_up(zAff + uintptr(j)))) != 0 {
|
|
**(**uint8)(__ccgo_up(zAff + uintptr(j))) = uint8(SQLITE_AFF_BLOB)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
j = j + 1
|
|
}
|
|
**(**uintptr)(__ccgo_up(pzAff)) = zAff
|
|
return regBase
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for the RETURNING trigger. Unlike other triggers
|
|
// ** that invoke a subprogram in the bytecode, the code for RETURNING
|
|
// ** is generated in-line.
|
|
// */
|
|
func _codeReturningTrigger(tls *libc.TLS, pParse uintptr, pTrigger uintptr, pTab uintptr, regIn int32) {
|
|
bp := tls.Alloc(272)
|
|
defer tls.Free(272)
|
|
var db, pCol, pFrom, pNew, pReturning, v, v2 uintptr
|
|
var i, nCol, reg, v1 int32
|
|
var _ /* sNC at bp+208 */ TNameContext
|
|
var _ /* sSelect at bp+0 */ TSelect
|
|
var _ /* uSrc at bp+120 */ struct {
|
|
FfromSpace [0][88]Tu8
|
|
FsSrc TSrcList
|
|
F__ccgo_pad2 [80]byte
|
|
}
|
|
_, _, _, _, _, _, _, _, _, _, _ = db, i, nCol, pCol, pFrom, pNew, pReturning, reg, v, v1, v2
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if !(int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40))&0x8>>3)) != 0) {
|
|
/* This RETURNING trigger must be for a different statement as
|
|
** this statement lacks a RETURNING clause. */
|
|
return
|
|
}
|
|
pReturning = (*(*struct {
|
|
FpReturning uintptr
|
|
})(unsafe.Pointer(&(*TParse)(unsafe.Pointer(pParse)).Fu1))).FpReturning
|
|
if pTrigger != pReturning+16 {
|
|
/* This RETURNING trigger is for a different statement */
|
|
return
|
|
}
|
|
libc.Xmemset(tls, bp, 0, uint64(120))
|
|
libc.Xmemset(tls, bp+120, 0, uint64(88))
|
|
pFrom = bp + 120
|
|
(**(**TSelect)(__ccgo_up(bp))).FpEList = _sqlite3ExprListDup(tls, db, (*TReturning)(unsafe.Pointer(pReturning)).FpReturnEL, 0)
|
|
(**(**TSelect)(__ccgo_up(bp))).FpSrc = pFrom
|
|
(*TSrcList)(unsafe.Pointer(pFrom)).FnSrc = int32(1)
|
|
(*(*TSrcItem)(unsafe.Pointer(pFrom + 8))).FpSTab = pTab
|
|
(*(*TSrcItem)(unsafe.Pointer(pFrom + 8))).FzName = (*TTable)(unsafe.Pointer(pTab)).FzName /* tag-20240424-1 */
|
|
(*(*TSrcItem)(unsafe.Pointer(pFrom + 8))).FiCursor = -int32(1)
|
|
_sqlite3SelectPrep(tls, pParse, bp, uintptr(0))
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr == 0 {
|
|
_sqlite3GenerateColumnNames(tls, pParse, bp)
|
|
}
|
|
_sqlite3ExprListDelete(tls, db, (**(**TSelect)(__ccgo_up(bp))).FpEList)
|
|
pNew = _sqlite3ExpandReturning(tls, pParse, (*TReturning)(unsafe.Pointer(pReturning)).FpReturnEL, pTab)
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr == 0 {
|
|
libc.Xmemset(tls, bp+208, 0, uint64(56))
|
|
if (*TReturning)(unsafe.Pointer(pReturning)).FnRetCol == 0 {
|
|
(*TReturning)(unsafe.Pointer(pReturning)).FnRetCol = (*TExprList)(unsafe.Pointer(pNew)).FnExpr
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
(*TReturning)(unsafe.Pointer(pReturning)).FiRetCur = v1
|
|
}
|
|
(**(**TNameContext)(__ccgo_up(bp + 208))).FpParse = pParse
|
|
*(*int32)(unsafe.Pointer(bp + 208 + 16)) = regIn
|
|
(**(**TNameContext)(__ccgo_up(bp + 208))).FncFlags = int32(NC_UBaseReg)
|
|
(*TParse)(unsafe.Pointer(pParse)).FeTriggerOp = (*TTrigger)(unsafe.Pointer(pTrigger)).Fop
|
|
(*TParse)(unsafe.Pointer(pParse)).FpTriggerTab = pTab
|
|
if _sqlite3ResolveExprListNames(tls, bp+208, pNew) == SQLITE_OK && !((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0) {
|
|
nCol = (*TExprList)(unsafe.Pointer(pNew)).FnExpr
|
|
reg = (*TParse)(unsafe.Pointer(pParse)).FnMem + int32(1)
|
|
_sqlite3ProcessReturningSubqueries(tls, pNew, pTab)
|
|
**(**int32)(__ccgo_up(pParse + 60)) += nCol + int32(2)
|
|
(*TReturning)(unsafe.Pointer(pReturning)).FiRetReg = reg
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
pCol = (*(*TExprList_item)(unsafe.Pointer(pNew + 8 + uintptr(i)*32))).FpExpr
|
|
/* Due to !db->mallocFailed ~9 lines above */
|
|
_sqlite3ExprCodeFactorable(tls, pParse, pCol, reg+i)
|
|
if libc.Int32FromUint8(_sqlite3ExprAffinity(tls, pCol)) == int32(SQLITE_AFF_REAL) {
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_RealAffinity), reg+i)
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_MakeRecord), reg, i, reg+i)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_NewRowid), (*TReturning)(unsafe.Pointer(pReturning)).FiRetCur, reg+i+int32(1))
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Insert), (*TReturning)(unsafe.Pointer(pReturning)).FiRetCur, reg+i, reg+i+int32(1))
|
|
}
|
|
}
|
|
_sqlite3ExprListDelete(tls, db, pNew)
|
|
(*TParse)(unsafe.Pointer(pParse)).FeTriggerOp = uint8(0)
|
|
(*TParse)(unsafe.Pointer(pParse)).FpTriggerTab = uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pExpr is a comparison operator. Return the type affinity that should
|
|
// ** be applied to both operands prior to doing the comparison.
|
|
// */
|
|
func _comparisonAffinity(tls *libc.TLS, pExpr uintptr) (r uint8) {
|
|
var aff uint8
|
|
_ = aff
|
|
aff = _sqlite3ExprAffinity(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft)
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FpRight != 0 {
|
|
aff = _sqlite3CompareAffinity(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, aff)
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
aff = _sqlite3CompareAffinity(tls, (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FpEList + 8))).FpExpr, aff)
|
|
} else {
|
|
if libc.Int32FromUint8(aff) == 0 {
|
|
aff = uint8(SQLITE_AFF_BLOB)
|
|
}
|
|
}
|
|
}
|
|
return aff
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if any of the result-set columns in the compound query
|
|
// ** have incompatible affinities on one or more arms of the compound.
|
|
// */
|
|
func _compoundHasDifferentAffinities(tls *libc.TLS, p uintptr) (r int32) {
|
|
var aff uint8
|
|
var ii int32
|
|
var pList, pSub1 uintptr
|
|
_, _, _, _ = aff, ii, pList, pSub1
|
|
pList = (*TSelect)(unsafe.Pointer(p)).FpEList
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
aff = _sqlite3ExprAffinity(tls, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(ii)*32))).FpExpr)
|
|
pSub1 = (*TSelect)(unsafe.Pointer(p)).FpPrior
|
|
for {
|
|
if !(pSub1 != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3ExprAffinity(tls, (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSub1)).FpEList + 8 + uintptr(ii)*32))).FpExpr)) != libc.Int32FromUint8(aff) {
|
|
return int32(1)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pSub1 = (*TSelect)(unsafe.Pointer(pSub1)).FpPrior
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return a pointer to the column affinity string associated with index
|
|
// ** pIdx. A column affinity string has one character for each column in
|
|
// ** the table, according to the affinity of the column:
|
|
// **
|
|
// ** Character Column affinity
|
|
// ** ------------------------------
|
|
// ** 'A' BLOB
|
|
// ** 'B' TEXT
|
|
// ** 'C' NUMERIC
|
|
// ** 'D' INTEGER
|
|
// ** 'F' REAL
|
|
// **
|
|
// ** An extra 'D' is appended to the end of the string to cover the
|
|
// ** rowid that appears as the last column in every index.
|
|
// **
|
|
// ** Memory for the buffer containing the column index affinity string
|
|
// ** is managed along with the rest of the Index structure. It will be
|
|
// ** released when sqlite3DeleteIndex() is called.
|
|
// */
|
|
func _computeIndexAffStr(tls *libc.TLS, db uintptr, pIdx uintptr) (r uintptr) {
|
|
var aff uint8
|
|
var n int32
|
|
var pTab uintptr
|
|
var x Ti16
|
|
_, _, _, _ = aff, n, pTab, x
|
|
pTab = (*TIndex)(unsafe.Pointer(pIdx)).FpTable
|
|
(*TIndex)(unsafe.Pointer(pIdx)).FzColAff = _sqlite3DbMallocRaw(tls, uintptr(0), libc.Uint64FromInt32(libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)+int32(1)))
|
|
if !((*TIndex)(unsafe.Pointer(pIdx)).FzColAff != 0) {
|
|
_sqlite3OomFault(tls, db)
|
|
return uintptr(0)
|
|
}
|
|
n = 0
|
|
for {
|
|
if !(n < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)) {
|
|
break
|
|
}
|
|
x = **(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(n)*2))
|
|
if int32(x) >= 0 {
|
|
aff = (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(x)*16))).Faffinity
|
|
} else {
|
|
if int32(x) == -int32(1) {
|
|
aff = uint8(SQLITE_AFF_INTEGER)
|
|
} else {
|
|
aff = _sqlite3ExprAffinity(tls, (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FaColExpr + 8 + uintptr(n)*32))).FpExpr)
|
|
}
|
|
}
|
|
if libc.Int32FromUint8(aff) < int32(SQLITE_AFF_BLOB) {
|
|
aff = uint8(SQLITE_AFF_BLOB)
|
|
}
|
|
if libc.Int32FromUint8(aff) > int32(SQLITE_AFF_NUMERIC) {
|
|
aff = uint8(SQLITE_AFF_NUMERIC)
|
|
}
|
|
**(**uint8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FzColAff + uintptr(n))) = aff
|
|
goto _1
|
|
_1:
|
|
;
|
|
n = n + 1
|
|
}
|
|
**(**uint8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FzColAff + uintptr(n))) = uint8(0)
|
|
return (*TIndex)(unsafe.Pointer(pIdx)).FzColAff
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* The core implementation of the CONCAT(...) and CONCAT_WS(SEP,...)
|
|
// ** functions.
|
|
// **
|
|
// ** Return a string value that is the concatenation of all non-null
|
|
// ** entries in argv[]. Use zSep as the separator.
|
|
// */
|
|
func _concatFuncCore(tls *libc.TLS, context uintptr, argc int32, argv uintptr, nSep int32, zSep uintptr) {
|
|
var bNotNull, i, k int32
|
|
var j, n Ti64
|
|
var v, z uintptr
|
|
_, _, _, _, _, _, _ = bNotNull, i, j, k, n, v, z
|
|
n = 0
|
|
bNotNull = 0
|
|
i = 0
|
|
for {
|
|
if !(i < argc) {
|
|
break
|
|
}
|
|
n = n + int64(Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8))))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
n = n + int64(argc-libc.Int32FromInt32(1))*int64(nSep)
|
|
z = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(n+int64(1)))
|
|
if z == uintptr(0) {
|
|
Xsqlite3_result_error_nomem(tls, context)
|
|
return
|
|
}
|
|
j = 0
|
|
i = 0
|
|
for {
|
|
if !(i < argc) {
|
|
break
|
|
}
|
|
if Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8))) != int32(SQLITE_NULL) {
|
|
k = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8)))
|
|
v = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8)))
|
|
if v != uintptr(0) {
|
|
if bNotNull != 0 && nSep > 0 {
|
|
libc.Xmemcpy(tls, z+uintptr(j), zSep, libc.Uint64FromInt32(nSep))
|
|
j = j + int64(nSep)
|
|
}
|
|
libc.Xmemcpy(tls, z+uintptr(j), v, libc.Uint64FromInt32(k))
|
|
j = j + int64(k)
|
|
bNotNull = int32(1)
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**uint8)(__ccgo_up(z + uintptr(j))) = uint8(0)
|
|
Xsqlite3_result_text64(tls, context, z, libc.Uint64FromInt64(j), __ccgo_fp(Xsqlite3_free), uint8(SQLITE_UTF8_ZT))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add a new entry to the pConst object. Except, do not add duplicate
|
|
// ** pColumn entries. Also, do not add if doing so would not be appropriate.
|
|
// **
|
|
// ** The caller guarantees the pColumn is a column and pValue is a constant.
|
|
// ** This routine has to do some additional checks before completing the
|
|
// ** insert.
|
|
// */
|
|
func _constInsert(tls *libc.TLS, pConst uintptr, pColumn uintptr, pValue uintptr, pExpr uintptr) {
|
|
var i int32
|
|
var pE2 uintptr
|
|
_, _ = i, pE2
|
|
if (*TExpr)(unsafe.Pointer(pColumn)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_FixedCol)) != uint32(0) {
|
|
return
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3ExprAffinity(tls, pValue)) != 0 {
|
|
return
|
|
}
|
|
if !(_sqlite3IsBinary(tls, _sqlite3ExprCompareCollSeq(tls, (*TWhereConst)(unsafe.Pointer(pConst)).FpParse, pExpr)) != 0) {
|
|
return
|
|
}
|
|
/* 2018-10-25 ticket [cf5ed20f]
|
|
** Make sure the same pColumn is not inserted more than once */
|
|
i = 0
|
|
for {
|
|
if !(i < (*TWhereConst)(unsafe.Pointer(pConst)).FnConst) {
|
|
break
|
|
}
|
|
pE2 = **(**uintptr)(__ccgo_up((*TWhereConst)(unsafe.Pointer(pConst)).FapExpr + uintptr(i*int32(2))*8))
|
|
if (*TExpr)(unsafe.Pointer(pE2)).FiTable == (*TExpr)(unsafe.Pointer(pColumn)).FiTable && int32((*TExpr)(unsafe.Pointer(pE2)).FiColumn) == int32((*TExpr)(unsafe.Pointer(pColumn)).FiColumn) {
|
|
return /* Already present. Return without doing anything. */
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3ExprAffinity(tls, pColumn)) <= int32(SQLITE_AFF_BLOB) {
|
|
(*TWhereConst)(unsafe.Pointer(pConst)).FbHasAffBlob = int32(1)
|
|
}
|
|
(*TWhereConst)(unsafe.Pointer(pConst)).FnConst = (*TWhereConst)(unsafe.Pointer(pConst)).FnConst + 1
|
|
(*TWhereConst)(unsafe.Pointer(pConst)).FapExpr = _sqlite3DbReallocOrFree(tls, (*TParse)(unsafe.Pointer((*TWhereConst)(unsafe.Pointer(pConst)).FpParse)).Fdb, (*TWhereConst)(unsafe.Pointer(pConst)).FapExpr, uint64(libc.Uint64FromInt32((*TWhereConst)(unsafe.Pointer(pConst)).FnConst*int32(2))*uint64(8)))
|
|
if (*TWhereConst)(unsafe.Pointer(pConst)).FapExpr == uintptr(0) {
|
|
(*TWhereConst)(unsafe.Pointer(pConst)).FnConst = 0
|
|
} else {
|
|
**(**uintptr)(__ccgo_up((*TWhereConst)(unsafe.Pointer(pConst)).FapExpr + uintptr((*TWhereConst)(unsafe.Pointer(pConst)).FnConst*int32(2)-int32(2))*8)) = pColumn
|
|
**(**uintptr)(__ccgo_up((*TWhereConst)(unsafe.Pointer(pConst)).FapExpr + uintptr((*TWhereConst)(unsafe.Pointer(pConst)).FnConst*int32(2)-int32(1))*8)) = pValue
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Analyze a term that consists of two or more OR-connected
|
|
// ** subterms. So in:
|
|
// **
|
|
// ** ... WHERE (a=5) AND (b=7 OR c=9 OR d=13) AND (d=13)
|
|
// ** ^^^^^^^^^^^^^^^^^^^^
|
|
// **
|
|
// ** This routine analyzes terms such as the middle term in the above example.
|
|
// ** A WhereOrTerm object is computed and attached to the term under
|
|
// ** analysis, regardless of the outcome of the analysis. Hence:
|
|
// **
|
|
// ** WhereTerm.wtFlags |= TERM_ORINFO
|
|
// ** WhereTerm.u.pOrInfo = a dynamically allocated WhereOrTerm object
|
|
// **
|
|
// ** The term being analyzed must have two or more of OR-connected subterms.
|
|
// ** A single subterm might be a set of AND-connected sub-subterms.
|
|
// ** Examples of terms under analysis:
|
|
// **
|
|
// ** (A) t1.x=t2.y OR t1.x=t2.z OR t1.y=15 OR t1.z=t3.a+5
|
|
// ** (B) x=expr1 OR expr2=x OR x=expr3
|
|
// ** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15)
|
|
// ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*')
|
|
// ** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6)
|
|
// ** (F) x>A OR (x=A AND y>=B)
|
|
// **
|
|
// ** CASE 1:
|
|
// **
|
|
// ** If all subterms are of the form T.C=expr for some single column of C and
|
|
// ** a single table T (as shown in example B above) then create a new virtual
|
|
// ** term that is an equivalent IN expression. In other words, if the term
|
|
// ** being analyzed is:
|
|
// **
|
|
// ** x = expr1 OR expr2 = x OR x = expr3
|
|
// **
|
|
// ** then create a new virtual term like this:
|
|
// **
|
|
// ** x IN (expr1,expr2,expr3)
|
|
// **
|
|
// ** CASE 2:
|
|
// **
|
|
// ** If there are exactly two disjuncts and one side has x>A and the other side
|
|
// ** has x=A (for the same x and A) then add a new virtual conjunct term to the
|
|
// ** WHERE clause of the form "x>=A". Example:
|
|
// **
|
|
// ** x>A OR (x=A AND y>B) adds: x>=A
|
|
// **
|
|
// ** The added conjunct can sometimes be helpful in query planning.
|
|
// **
|
|
// ** CASE 3:
|
|
// **
|
|
// ** If all subterms are indexable by a single table T, then set
|
|
// **
|
|
// ** WhereTerm.eOperator = WO_OR
|
|
// ** WhereTerm.u.pOrInfo->indexable |= the cursor number for table T
|
|
// **
|
|
// ** A subterm is "indexable" if it is of the form
|
|
// ** "T.C <op> <expr>" where C is any column of table T and
|
|
// ** <op> is one of "=", "<", "<=", ">", ">=", "IS NULL", or "IN".
|
|
// ** A subterm is also indexable if it is an AND of two or more
|
|
// ** subsubterms at least one of which is indexable. Indexable AND
|
|
// ** subterms have their eOperator set to WO_AND and they have
|
|
// ** u.pAndInfo set to a dynamically allocated WhereAndTerm object.
|
|
// **
|
|
// ** From another point of view, "indexable" means that the subterm could
|
|
// ** potentially be used with an index if an appropriate index exists.
|
|
// ** This analysis does not consider whether or not the index exists; that
|
|
// ** is decided elsewhere. This analysis only looks at whether subterms
|
|
// ** appropriate for indexing exist.
|
|
// **
|
|
// ** All examples A through E above satisfy case 3. But if a term
|
|
// ** also satisfies case 1 (such as B) we know that the optimizer will
|
|
// ** always prefer case 1, so in that case we pretend that case 3 is not
|
|
// ** satisfied.
|
|
// **
|
|
// ** It might be the case that multiple tables are indexable. For example,
|
|
// ** (E) above is indexable on tables P, Q, and R.
|
|
// **
|
|
// ** Terms that satisfy case 3 are candidates for lookup by using
|
|
// ** separate indices to find rowids for each subterm and composing
|
|
// ** the union of all rowids using a RowSet object. This is similar
|
|
// ** to "bitmap indices" in other database engines.
|
|
// **
|
|
// ** OTHERWISE:
|
|
// **
|
|
// ** If none of cases 1, 2, or 3 apply, then leave the eOperator set to
|
|
// ** zero. This term is not useful for search.
|
|
// */
|
|
func _exprAnalyzeOrTerm(tls *libc.TLS, pSrc uintptr, pWC uintptr, idxTerm int32) {
|
|
var affLeft, affRight, i, iColumn, iCursor, iOne, iTwo, idxNew, j, j1, okToChngToIN, v7, v9 int32
|
|
var b, b1, chngToIN, indexable TBitmask
|
|
var db, pAndInfo, pAndTerm, pAndWC, pDup, pExpr, pLeft, pLeft1, pList, pNew, pOne, pOrInfo, pOrTerm, pOrWc, pOther, pParse, pTerm, pTwo, pWInfo, v1, v2 uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = affLeft, affRight, b, b1, chngToIN, db, i, iColumn, iCursor, iOne, iTwo, idxNew, indexable, j, j1, okToChngToIN, pAndInfo, pAndTerm, pAndWC, pDup, pExpr, pLeft, pLeft1, pList, pNew, pOne, pOrInfo, pOrTerm, pOrWc, pOther, pParse, pTerm, pTwo, pWInfo, v1, v2, v7, v9
|
|
pWInfo = (*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo /* WHERE clause processing context */
|
|
pParse = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse /* Parser context */
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* Database connection */
|
|
pTerm = (*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(idxTerm)*56 /* The term to be analyzed */
|
|
pExpr = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr /* Tables that are indexable, satisfying case 2 */
|
|
/*
|
|
** Break the OR clause into its separate subterms. The subterms are
|
|
** stored in a WhereClause structure containing within the WhereOrInfo
|
|
** object that is attached to the original OR clause term.
|
|
*/
|
|
v1 = _sqlite3DbMallocZero(tls, db, uint64(496))
|
|
pOrInfo = v1
|
|
*(*uintptr)(unsafe.Pointer(pTerm + 32)) = v1
|
|
if pOrInfo == uintptr(0) {
|
|
return
|
|
}
|
|
v1 = pTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(TERM_ORINFO))
|
|
pOrWc = pOrInfo
|
|
libc.Xmemset(tls, pOrWc+40, 0, uint64(448))
|
|
_sqlite3WhereClauseInit(tls, pOrWc, pWInfo)
|
|
_sqlite3WhereSplit(tls, pOrWc, pExpr, uint8(TK_OR))
|
|
_sqlite3WhereExprAnalyze(tls, pSrc, pOrWc)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
return
|
|
}
|
|
/*
|
|
** Compute the set of tables that might satisfy cases 1 or 3.
|
|
*/
|
|
indexable = ^libc.Uint64FromInt32(0)
|
|
chngToIN = ^libc.Uint64FromInt32(0)
|
|
i = (*TWhereClause)(unsafe.Pointer(pOrWc)).FnTerm - int32(1)
|
|
pOrTerm = (*TWhereClause)(unsafe.Pointer(pOrWc)).Fa
|
|
for {
|
|
if !(i >= 0 && indexable != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FeOperator)&int32(WO_SINGLE) == 0 {
|
|
chngToIN = uint64(0)
|
|
pAndInfo = _sqlite3DbMallocRawNN(tls, db, uint64(488))
|
|
if pAndInfo != 0 {
|
|
b = uint64(0)
|
|
*(*uintptr)(unsafe.Pointer(pOrTerm + 32)) = pAndInfo
|
|
v1 = pOrTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(TERM_ANDINFO))
|
|
(*TWhereTerm)(unsafe.Pointer(pOrTerm)).FeOperator = uint16(WO_AND)
|
|
(*TWhereTerm)(unsafe.Pointer(pOrTerm)).FleftCursor = -int32(1)
|
|
pAndWC = pAndInfo
|
|
libc.Xmemset(tls, pAndWC+40, 0, uint64(448))
|
|
_sqlite3WhereClauseInit(tls, pAndWC, (*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo)
|
|
_sqlite3WhereSplit(tls, pAndWC, (*TWhereTerm)(unsafe.Pointer(pOrTerm)).FpExpr, uint8(TK_AND))
|
|
_sqlite3WhereExprAnalyze(tls, pSrc, pAndWC)
|
|
(*TWhereClause)(unsafe.Pointer(pAndWC)).FpOuter = pWC
|
|
if !((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0) {
|
|
j = 0
|
|
pAndTerm = (*TWhereClause)(unsafe.Pointer(pAndWC)).Fa
|
|
for {
|
|
if !(j < (*TWhereClause)(unsafe.Pointer(pAndWC)).FnTerm) {
|
|
break
|
|
}
|
|
if _allowedOp(tls, libc.Int32FromUint8((*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pAndTerm)).FpExpr)).Fop)) != 0 || libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pAndTerm)).FeOperator) == int32(WO_AUX) {
|
|
b = b | _sqlite3WhereGetMask(tls, pWInfo+592, (*TWhereTerm)(unsafe.Pointer(pAndTerm)).FleftCursor)
|
|
}
|
|
goto _5
|
|
_5:
|
|
;
|
|
j = j + 1
|
|
pAndTerm += 56
|
|
}
|
|
}
|
|
indexable = indexable & b
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FwtFlags)&int32(TERM_COPIED) != 0 {
|
|
/* Skip this term for now. We revisit it when we process the
|
|
** corresponding TERM_VIRTUAL term */
|
|
} else {
|
|
b1 = _sqlite3WhereGetMask(tls, pWInfo+592, (*TWhereTerm)(unsafe.Pointer(pOrTerm)).FleftCursor)
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FwtFlags)&int32(TERM_VIRTUAL) != 0 {
|
|
pOther = (*TWhereClause)(unsafe.Pointer(pOrWc)).Fa + uintptr((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FiParent)*56
|
|
b1 = b1 | _sqlite3WhereGetMask(tls, pWInfo+592, (*TWhereTerm)(unsafe.Pointer(pOther)).FleftCursor)
|
|
}
|
|
indexable = indexable & b1
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FeOperator)&int32(WO_EQ) == 0 {
|
|
chngToIN = uint64(0)
|
|
} else {
|
|
chngToIN = chngToIN & b1
|
|
}
|
|
}
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i - 1
|
|
pOrTerm += 56
|
|
}
|
|
/*
|
|
** Record the set of tables that satisfy case 3. The set might be
|
|
** empty.
|
|
*/
|
|
(*TWhereOrInfo)(unsafe.Pointer(pOrInfo)).Findexable = indexable
|
|
(*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator = uint16(WO_OR)
|
|
(*TWhereTerm)(unsafe.Pointer(pTerm)).FleftCursor = -int32(1)
|
|
if indexable != 0 {
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).FhasOr = uint8(1)
|
|
}
|
|
/* For a two-way OR, attempt to implementation case 2.
|
|
*/
|
|
if indexable != 0 && (*TWhereClause)(unsafe.Pointer(pOrWc)).FnTerm == int32(2) {
|
|
iOne = 0
|
|
for {
|
|
v7 = iOne
|
|
iOne = iOne + 1
|
|
v1 = _whereNthSubterm(tls, (*TWhereClause)(unsafe.Pointer(pOrWc)).Fa, v7)
|
|
pOne = v1
|
|
if !(v1 != uintptr(0)) {
|
|
break
|
|
}
|
|
iTwo = 0
|
|
for {
|
|
v9 = iTwo
|
|
iTwo = iTwo + 1
|
|
v2 = _whereNthSubterm(tls, (*TWhereClause)(unsafe.Pointer(pOrWc)).Fa+1*56, v9)
|
|
pTwo = v2
|
|
if !(v2 != uintptr(0)) {
|
|
break
|
|
}
|
|
_whereCombineDisjuncts(tls, pSrc, pWC, pOne, pTwo)
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
** chngToIN holds a set of tables that *might* satisfy case 1. But
|
|
** we have to do some additional checking to see if case 1 really
|
|
** is satisfied.
|
|
**
|
|
** chngToIN will hold either 0, 1, or 2 bits. The 0-bit case means
|
|
** that there is no possibility of transforming the OR clause into an
|
|
** IN operator because one or more terms in the OR clause contain
|
|
** something other than == on a column in the single table. The 1-bit
|
|
** case means that every term of the OR clause is of the form
|
|
** "table.column=expr" for some single table. The one bit that is set
|
|
** will correspond to the common table. We still need to check to make
|
|
** sure the same column is used on all terms. The 2-bit case is when
|
|
** the all terms are of the form "table1.column=table2.column". It
|
|
** might be possible to form an IN operator with either table1.column
|
|
** or table2.column as the LHS if either is common to every term of
|
|
** the OR clause.
|
|
**
|
|
** Note that terms of the form "table.column1=table.column2" (the
|
|
** same table on both sizes of the ==) cannot be optimized.
|
|
*/
|
|
if chngToIN != 0 {
|
|
okToChngToIN = 0 /* True if the conversion to IN is valid */
|
|
iColumn = -int32(1) /* Column index on lhs of IN operator */
|
|
iCursor = -int32(1) /* Table cursor common to all terms */
|
|
j1 = 0 /* Loop counter */
|
|
/* Search for a table and column that appears on one side or the
|
|
** other of the == operator in every subterm. That table and column
|
|
** will be recorded in iCursor and iColumn. There might not be any
|
|
** such table and column. Set okToChngToIN if an appropriate table
|
|
** and column is found but leave okToChngToIN false if not found.
|
|
*/
|
|
j1 = 0
|
|
for {
|
|
if !(j1 < int32(2) && !(okToChngToIN != 0)) {
|
|
break
|
|
}
|
|
pLeft = uintptr(0)
|
|
pOrTerm = (*TWhereClause)(unsafe.Pointer(pOrWc)).Fa
|
|
i = (*TWhereClause)(unsafe.Pointer(pOrWc)).FnTerm - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
v1 = pOrTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(TERM_OK))
|
|
if (*TWhereTerm)(unsafe.Pointer(pOrTerm)).FleftCursor == iCursor {
|
|
/* This is the 2-bit case and we are on the second iteration and
|
|
** current term is from the first iteration. So skip this term. */
|
|
goto _11
|
|
}
|
|
if chngToIN&_sqlite3WhereGetMask(tls, pWInfo+592, (*TWhereTerm)(unsafe.Pointer(pOrTerm)).FleftCursor) == uint64(0) {
|
|
/* This term must be of the form t1.a==t2.b where t2 is in the
|
|
** chngToIN set but t1 is not. This term will be either preceded
|
|
** or followed by an inverted copy (t2.b==t1.a). Skip this term
|
|
** and use its inversion. */
|
|
goto _11
|
|
}
|
|
iColumn = (*(*struct {
|
|
FleftColumn int32
|
|
FiField int32
|
|
})(unsafe.Pointer(pOrTerm + 32))).FleftColumn
|
|
iCursor = (*TWhereTerm)(unsafe.Pointer(pOrTerm)).FleftCursor
|
|
pLeft = (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FpExpr)).FpLeft
|
|
break
|
|
goto _11
|
|
_11:
|
|
;
|
|
i = i - 1
|
|
pOrTerm += 56
|
|
}
|
|
if i < 0 {
|
|
/* No candidate table+column was found. This can only occur
|
|
** on the second iteration */
|
|
break
|
|
}
|
|
/* We have found a candidate table and column. Check to see if that
|
|
** table and column is common to every term in the OR clause */
|
|
okToChngToIN = int32(1)
|
|
for {
|
|
if !(i >= 0 && okToChngToIN != 0) {
|
|
break
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(pOrTerm)).FleftCursor != iCursor {
|
|
v1 = pOrTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(TERM_OK))
|
|
} else {
|
|
if (*(*struct {
|
|
FleftColumn int32
|
|
FiField int32
|
|
})(unsafe.Pointer(pOrTerm + 32))).FleftColumn != iColumn || iColumn == -int32(2) && _sqlite3ExprCompare(tls, pParse, (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FpExpr)).FpLeft, pLeft, -int32(1)) != 0 {
|
|
okToChngToIN = 0
|
|
} else {
|
|
/* If the right-hand side is also a column, then the affinities
|
|
** of both right and left sides must be such that no type
|
|
** conversions are required on the right. (Ticket #2249)
|
|
*/
|
|
affRight = libc.Int32FromUint8(_sqlite3ExprAffinity(tls, (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FpExpr)).FpRight))
|
|
affLeft = libc.Int32FromUint8(_sqlite3ExprAffinity(tls, (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FpExpr)).FpLeft))
|
|
if affRight != 0 && affRight != affLeft {
|
|
okToChngToIN = 0
|
|
} else {
|
|
v1 = pOrTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(TERM_OK))
|
|
}
|
|
}
|
|
}
|
|
goto _13
|
|
_13:
|
|
;
|
|
i = i - 1
|
|
pOrTerm += 56
|
|
}
|
|
goto _10
|
|
_10:
|
|
;
|
|
j1 = j1 + 1
|
|
}
|
|
/* At this point, okToChngToIN is true if original pTerm satisfies
|
|
** case 1. In that case, construct a new virtual term that is
|
|
** pTerm converted into an IN operator.
|
|
*/
|
|
if okToChngToIN != 0 { /* A transient duplicate expression */
|
|
pList = uintptr(0) /* The RHS of the IN operator */
|
|
pLeft1 = uintptr(0) /* The complete IN operator */
|
|
i = (*TWhereClause)(unsafe.Pointer(pOrWc)).FnTerm - int32(1)
|
|
pOrTerm = (*TWhereClause)(unsafe.Pointer(pOrWc)).Fa
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FwtFlags)&int32(TERM_OK) == 0 {
|
|
goto _16
|
|
}
|
|
pDup = _sqlite3ExprDup(tls, db, (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FpExpr)).FpRight, 0)
|
|
pList = _sqlite3ExprListAppend(tls, (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse, pList, pDup)
|
|
pLeft1 = (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pOrTerm)).FpExpr)).FpLeft
|
|
goto _16
|
|
_16:
|
|
;
|
|
i = i - 1
|
|
pOrTerm += 56
|
|
}
|
|
pDup = _sqlite3ExprDup(tls, db, pLeft1, 0)
|
|
pNew = _sqlite3PExpr(tls, pParse, int32(TK_IN), pDup, uintptr(0))
|
|
if pNew != 0 {
|
|
_transferJoinMarkings(tls, pNew, pExpr)
|
|
*(*uintptr)(unsafe.Pointer(pNew + 32)) = pList
|
|
idxNew = _whereClauseInsert(tls, pWC, pNew, libc.Uint16FromInt32(libc.Int32FromInt32(TERM_VIRTUAL)|libc.Int32FromInt32(TERM_DYNAMIC)))
|
|
_exprAnalyze(tls, pSrc, pWC, idxNew)
|
|
/* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where reused */
|
|
_markTermAsChild(tls, pWC, idxNew, idxTerm)
|
|
} else {
|
|
_sqlite3ExprListDelete(tls, db, pList)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Argument pExpr is an (?, ?...) IN(...) expression. This
|
|
// ** function allocates and returns a nul-terminated string containing
|
|
// ** the affinities to be used for each column of the comparison.
|
|
// **
|
|
// ** It is the responsibility of the caller to ensure that the returned
|
|
// ** string is eventually freed using sqlite3DbFree().
|
|
// */
|
|
func _exprINAffinity(tls *libc.TLS, pParse uintptr, pExpr uintptr) (r uintptr) {
|
|
var a uint8
|
|
var i, nVal int32
|
|
var pA, pLeft, pSelect, zRet, v1 uintptr
|
|
_, _, _, _, _, _, _, _ = a, i, nVal, pA, pLeft, pSelect, zRet, v1
|
|
pLeft = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
nVal = _sqlite3ExprVectorSize(tls, pLeft)
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
v1 = *(*uintptr)(unsafe.Pointer(pExpr + 32))
|
|
} else {
|
|
v1 = uintptr(0)
|
|
}
|
|
pSelect = v1
|
|
zRet = _sqlite3DbMallocRaw(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, libc.Uint64FromInt64(int64(1)+int64(nVal)))
|
|
if zRet != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < nVal) {
|
|
break
|
|
}
|
|
pA = _sqlite3VectorFieldSubexpr(tls, pLeft, i)
|
|
a = _sqlite3ExprAffinity(tls, pA)
|
|
if pSelect != 0 {
|
|
**(**uint8)(__ccgo_up(zRet + uintptr(i))) = _sqlite3CompareAffinity(tls, (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpEList + 8 + uintptr(i)*32))).FpExpr, a)
|
|
} else {
|
|
**(**uint8)(__ccgo_up(zRet + uintptr(i))) = a
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**uint8)(__ccgo_up(zRet + uintptr(nVal))) = uint8('\000')
|
|
}
|
|
return zRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if all expressions in the expression-list passed as the
|
|
// ** only argument are both constant and have no affinity.
|
|
// */
|
|
func _exprListIsNoAffinity(tls *libc.TLS, pParse uintptr, pRow uintptr) (r int32) {
|
|
var ii int32
|
|
var pExpr uintptr
|
|
_, _ = ii, pExpr
|
|
if _exprListIsConstant(tls, pParse, pRow) == 0 {
|
|
return 0
|
|
}
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TExprList)(unsafe.Pointer(pRow)).FnExpr) {
|
|
break
|
|
}
|
|
pExpr = (*(*TExprList_item)(unsafe.Pointer(pRow + 8 + uintptr(ii)*32))).FpExpr
|
|
if 0 != libc.Int32FromUint8(_sqlite3ExprAffinity(tls, pExpr)) {
|
|
return 0
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return an Expr object that refers to a memory register corresponding
|
|
// ** to column iCol of table pTab.
|
|
// **
|
|
// ** regBase is the first of an array of register that contains the data
|
|
// ** for pTab. regBase itself holds the rowid. regBase+1 holds the first
|
|
// ** column. regBase+2 holds the second column, and so forth.
|
|
// */
|
|
func _exprTableRegister(tls *libc.TLS, pParse uintptr, pTab uintptr, regBase int32, iCol Ti16) (r uintptr) {
|
|
var db, pCol, pExpr, zColl uintptr
|
|
_, _, _, _ = db, pCol, pExpr, zColl
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pExpr = _sqlite3Expr(tls, db, int32(TK_REGISTER), uintptr(0))
|
|
if pExpr != 0 {
|
|
if int32(iCol) >= 0 && int32(iCol) != int32((*TTable)(unsafe.Pointer(pTab)).FiPKey) {
|
|
pCol = (*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(iCol)*16
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FiTable = regBase + int32(_sqlite3TableColumnToStorage(tls, pTab, iCol)) + int32(1)
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FaffExpr = (*TColumn)(unsafe.Pointer(pCol)).Faffinity
|
|
zColl = _sqlite3ColumnColl(tls, pCol)
|
|
if zColl == uintptr(0) {
|
|
zColl = (*TCollSeq)(unsafe.Pointer((*Tsqlite3)(unsafe.Pointer(db)).FpDfltColl)).FzName
|
|
}
|
|
pExpr = _sqlite3ExprAddCollateString(tls, pParse, pExpr, zColl)
|
|
} else {
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FiTable = regBase
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FaffExpr = uint8(SQLITE_AFF_INTEGER)
|
|
}
|
|
}
|
|
return pExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Gobble up the first bareword or quoted word from the input buffer zIn.
|
|
// ** Return a pointer to the character immediately following the last in
|
|
// ** the gobbled word if successful, or a NULL pointer otherwise (failed
|
|
// ** to find close-quote character).
|
|
// **
|
|
// ** Before returning, set pzOut to point to a new buffer containing a
|
|
// ** nul-terminated, dequoted copy of the gobbled word. If the word was
|
|
// ** quoted, *pbQuoted is also set to 1 before returning.
|
|
// **
|
|
// ** If *pRc is other than SQLITE_OK when this function is called, it is
|
|
// ** a no-op (NULL is returned). Otherwise, if an OOM occurs within this
|
|
// ** function, *pRc is set to SQLITE_NOMEM before returning. *pRc is *not*
|
|
// ** set if a parse error (failed to find close quote) occurs.
|
|
// */
|
|
func _fts5ConfigGobbleWord(tls *libc.TLS, pRc uintptr, zIn uintptr, pzOut uintptr, pbQuoted uintptr) (r uintptr) {
|
|
var ii int32
|
|
var nIn Tsqlite3_int64
|
|
var zOut, zRet uintptr
|
|
_, _, _, _ = ii, nIn, zOut, zRet
|
|
zRet = uintptr(0)
|
|
nIn = libc.Int64FromUint64(libc.Xstrlen(tls, zIn))
|
|
zOut = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(nIn+int64(1)))
|
|
**(**int32)(__ccgo_up(pbQuoted)) = 0
|
|
**(**uintptr)(__ccgo_up(pzOut)) = uintptr(0)
|
|
if zOut == uintptr(0) {
|
|
**(**int32)(__ccgo_up(pRc)) = int32(SQLITE_NOMEM)
|
|
} else {
|
|
libc.Xmemcpy(tls, zOut, zIn, libc.Uint64FromInt64(nIn+libc.Int64FromInt32(1)))
|
|
if _fts5_isopenquote(tls, **(**uint8)(__ccgo_up(zOut))) != 0 {
|
|
ii = _fts5Dequote(tls, zOut)
|
|
zRet = zIn + uintptr(ii)
|
|
**(**int32)(__ccgo_up(pbQuoted)) = int32(1)
|
|
} else {
|
|
zRet = _fts5ConfigSkipBareword(tls, zIn)
|
|
if zRet != 0 {
|
|
**(**uint8)(__ccgo_up(zOut + uintptr(int64(zRet)-int64(zIn)))) = uint8('\000')
|
|
}
|
|
}
|
|
}
|
|
if zRet == uintptr(0) {
|
|
Xsqlite3_free(tls, zOut)
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(pzOut)) = zOut
|
|
}
|
|
return zRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of fts5_locale(LOCALE, TEXT) function.
|
|
// **
|
|
// ** If parameter LOCALE is NULL, or a zero-length string, then a copy of
|
|
// ** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as
|
|
// ** text, and the value returned is a blob consisting of:
|
|
// **
|
|
// ** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER).
|
|
// ** * The LOCALE, as utf-8 text, followed by
|
|
// ** * 0x00, followed by
|
|
// ** * The TEXT, as utf-8 text.
|
|
// **
|
|
// ** There is no final nul-terminator following the TEXT value.
|
|
// */
|
|
func _fts5LocaleFunc(tls *libc.TLS, pCtx uintptr, nArg int32, apArg uintptr) {
|
|
var nBlob, nLocale, nText Ti64
|
|
var p, pBlob, pCsr, zLocale, zText, v1 uintptr
|
|
_, _, _, _, _, _, _, _, _ = nBlob, nLocale, nText, p, pBlob, pCsr, zLocale, zText, v1
|
|
zLocale = uintptr(0)
|
|
nLocale = 0
|
|
zText = uintptr(0)
|
|
nText = 0
|
|
_ = nArg
|
|
zLocale = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(apArg)))
|
|
nLocale = int64(Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(apArg))))
|
|
zText = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(apArg + 1*8)))
|
|
nText = int64(Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(apArg + 1*8))))
|
|
if zLocale == uintptr(0) || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zLocale))) == int32('\000') {
|
|
Xsqlite3_result_text(tls, pCtx, zText, int32(nText), uintptr(-libc.Int32FromInt32(1)))
|
|
} else {
|
|
p = Xsqlite3_user_data(tls, pCtx)
|
|
pBlob = uintptr(0)
|
|
pCsr = uintptr(0)
|
|
nBlob = 0
|
|
nBlob = int64(libc.Int32FromInt64(16)) + nLocale + int64(1) + nText
|
|
pBlob = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(nBlob))
|
|
if pBlob == uintptr(0) {
|
|
Xsqlite3_result_error_nomem(tls, pCtx)
|
|
return
|
|
}
|
|
pCsr = pBlob
|
|
libc.Xmemcpy(tls, pCsr, p+96, libc.Uint64FromInt32(libc.Int32FromInt64(16)))
|
|
pCsr = pCsr + uintptr(libc.Int32FromInt64(16))
|
|
libc.Xmemcpy(tls, pCsr, zLocale, libc.Uint64FromInt64(nLocale))
|
|
pCsr = pCsr + uintptr(nLocale)
|
|
v1 = pCsr
|
|
pCsr = pCsr + 1
|
|
**(**Tu8)(__ccgo_up(v1)) = uint8(0x00)
|
|
if zText != 0 {
|
|
libc.Xmemcpy(tls, pCsr, zText, libc.Uint64FromInt64(nText))
|
|
}
|
|
Xsqlite3_result_blob(tls, pCtx, pBlob, int32(nBlob), __ccgo_fp(Xsqlite3_free))
|
|
}
|
|
}
|
|
|
|
func _fts5PorterCb(tls *libc.TLS, pCtx uintptr, tflags int32, pToken uintptr, nToken int32, iStart int32, iEnd int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var aBuf, p uintptr
|
|
var c uint8
|
|
var v1 int32
|
|
var _ /* nBuf at bp+0 */ int32
|
|
_, _, _, _ = aBuf, c, p, v1
|
|
p = pCtx
|
|
if nToken > int32(FTS5_PORTER_MAX_TOKEN) || nToken < int32(3) {
|
|
goto pass_through
|
|
}
|
|
aBuf = (*TPorterContext)(unsafe.Pointer(p)).FaBuf
|
|
**(**int32)(__ccgo_up(bp)) = nToken
|
|
libc.Xmemcpy(tls, aBuf, pToken, libc.Uint64FromInt32(**(**int32)(__ccgo_up(bp))))
|
|
/* Step 1. */
|
|
_fts5PorterStep1A(tls, aBuf, bp)
|
|
if _fts5PorterStep1B(tls, aBuf, bp) != 0 {
|
|
if _fts5PorterStep1B2(tls, aBuf, bp) == 0 {
|
|
c = **(**uint8)(__ccgo_up(aBuf + uintptr(**(**int32)(__ccgo_up(bp))-int32(1))))
|
|
if _fts5PorterIsVowel(tls, c, 0) == 0 && libc.Int32FromUint8(c) != int32('l') && libc.Int32FromUint8(c) != int32('s') && libc.Int32FromUint8(c) != int32('z') && libc.Int32FromUint8(c) == libc.Int32FromUint8(**(**uint8)(__ccgo_up(aBuf + uintptr(**(**int32)(__ccgo_up(bp))-int32(2))))) {
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) - 1
|
|
} else {
|
|
if _fts5Porter_MEq1(tls, aBuf, **(**int32)(__ccgo_up(bp))) != 0 && _fts5Porter_Ostar(tls, aBuf, **(**int32)(__ccgo_up(bp))) != 0 {
|
|
v1 = **(**int32)(__ccgo_up(bp))
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) + 1
|
|
**(**uint8)(__ccgo_up(aBuf + uintptr(v1))) = uint8('e')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* Step 1C. */
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(aBuf + uintptr(**(**int32)(__ccgo_up(bp))-int32(1))))) == int32('y') && _fts5Porter_Vowel(tls, aBuf, **(**int32)(__ccgo_up(bp))-int32(1)) != 0 {
|
|
**(**uint8)(__ccgo_up(aBuf + uintptr(**(**int32)(__ccgo_up(bp))-int32(1)))) = uint8('i')
|
|
}
|
|
/* Steps 2 through 4. */
|
|
_fts5PorterStep2(tls, aBuf, bp)
|
|
_fts5PorterStep3(tls, aBuf, bp)
|
|
_fts5PorterStep4(tls, aBuf, bp)
|
|
/* Step 5a. */
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(aBuf + uintptr(**(**int32)(__ccgo_up(bp))-int32(1))))) == int32('e') {
|
|
if _fts5Porter_MGt1(tls, aBuf, **(**int32)(__ccgo_up(bp))-int32(1)) != 0 || _fts5Porter_MEq1(tls, aBuf, **(**int32)(__ccgo_up(bp))-int32(1)) != 0 && !(_fts5Porter_Ostar(tls, aBuf, **(**int32)(__ccgo_up(bp))-int32(1)) != 0) {
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) - 1
|
|
}
|
|
}
|
|
/* Step 5b. */
|
|
if **(**int32)(__ccgo_up(bp)) > int32(1) && libc.Int32FromUint8(**(**uint8)(__ccgo_up(aBuf + uintptr(**(**int32)(__ccgo_up(bp))-int32(1))))) == int32('l') && libc.Int32FromUint8(**(**uint8)(__ccgo_up(aBuf + uintptr(**(**int32)(__ccgo_up(bp))-int32(2))))) == int32('l') && _fts5Porter_MGt1(tls, aBuf, **(**int32)(__ccgo_up(bp))-int32(1)) != 0 {
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) - 1
|
|
}
|
|
return (*(*func(*libc.TLS, uintptr, int32, uintptr, int32, int32, int32) int32)(unsafe.Pointer(&struct{ uintptr }{(*TPorterContext)(unsafe.Pointer(p)).FxToken})))(tls, (*TPorterContext)(unsafe.Pointer(p)).FpCtx, tflags, aBuf, **(**int32)(__ccgo_up(bp)), iStart, iEnd)
|
|
goto pass_through
|
|
pass_through:
|
|
;
|
|
return (*(*func(*libc.TLS, uintptr, int32, uintptr, int32, int32, int32) int32)(unsafe.Pointer(&struct{ uintptr }{(*TPorterContext)(unsafe.Pointer(p)).FxToken})))(tls, (*TPorterContext)(unsafe.Pointer(p)).FpCtx, tflags, pToken, nToken, iStart, iEnd)
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Trigram tokenizer tokenize routine.
|
|
// */
|
|
func _fts5TriTokenize(tls *libc.TLS, pTok uintptr, pCtx uintptr, unusedFlags int32, pText uintptr, nText int32, __ccgo_fp_xToken uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var aStart [3]int32
|
|
var iCode Tu32
|
|
var iNext, ii, rc int32
|
|
var p, z1, zEof, zIn, zOut, v1 uintptr
|
|
var _ /* aBuf at bp+0 */ [32]uint8
|
|
_, _, _, _, _, _, _, _, _, _, _ = aStart, iCode, iNext, ii, p, rc, z1, zEof, zIn, zOut, v1
|
|
p = pTok
|
|
rc = SQLITE_OK
|
|
zOut = bp
|
|
zIn = pText
|
|
if zIn != 0 {
|
|
v1 = zIn + uintptr(nText)
|
|
} else {
|
|
v1 = uintptr(0)
|
|
}
|
|
zEof = v1
|
|
iCode = uint32(0) /* Input offset of each character in aBuf[] */
|
|
_ = unusedFlags
|
|
/* Populate aBuf[] with the characters for the first trigram. */
|
|
ii = 0
|
|
for {
|
|
if !(ii < int32(3)) {
|
|
break
|
|
}
|
|
for cond := true; cond; cond = iCode == uint32(0) {
|
|
aStart[ii] = int32(int64(zIn) - int64(pText))
|
|
if zIn >= zEof {
|
|
return SQLITE_OK
|
|
}
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
iCode = uint32(**(**uint8)(__ccgo_up(v1)))
|
|
if iCode >= uint32(0xc0) {
|
|
iCode = uint32(_sqlite3Utf8Trans1[iCode-uint32(0xc0)])
|
|
for zIn < zEof && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zIn)))&int32(0xc0) == int32(0x80) {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
iCode = iCode<<libc.Int32FromInt32(6) + libc.Uint32FromInt32(libc.Int32FromInt32(0x3f)&libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1))))
|
|
}
|
|
if iCode < uint32(0x80) || iCode&uint32(0xFFFFF800) == uint32(0xD800) || iCode&uint32(0xFFFFFFFE) == uint32(0xFFFE) {
|
|
iCode = uint32(0xFFFD)
|
|
}
|
|
}
|
|
if (*TTrigramTokenizer)(unsafe.Pointer(p)).FbFold != 0 {
|
|
iCode = libc.Uint32FromInt32(_sqlite3Fts5UnicodeFold(tls, libc.Int32FromUint32(iCode), (*TTrigramTokenizer)(unsafe.Pointer(p)).FiFoldParam))
|
|
}
|
|
}
|
|
if iCode < uint32(0x00080) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(iCode & libc.Uint32FromInt32(0xFF))
|
|
} else {
|
|
if iCode < uint32(0x00800) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xC0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x1F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
if iCode < uint32(0x10000) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xE0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x0F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xF0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(18)&libc.Uint32FromInt32(0x07))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
}
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
/* At the start of each iteration of this loop:
|
|
**
|
|
** aBuf: Contains 3 characters. The 3 characters of the next trigram.
|
|
** zOut: Points to the byte following the last character in aBuf.
|
|
** aStart[3]: Contains the byte offset in the input text corresponding
|
|
** to the start of each of the three characters in the buffer.
|
|
*/
|
|
for int32(1) != 0 {
|
|
/* Read characters from the input up until the first non-diacritic */
|
|
for cond := true; cond; cond = iCode == uint32(0) {
|
|
iNext = int32(int64(zIn) - int64(pText))
|
|
if zIn >= zEof {
|
|
iCode = uint32(0)
|
|
break
|
|
}
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
iCode = uint32(**(**uint8)(__ccgo_up(v1)))
|
|
if iCode >= uint32(0xc0) {
|
|
iCode = uint32(_sqlite3Utf8Trans1[iCode-uint32(0xc0)])
|
|
for zIn < zEof && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zIn)))&int32(0xc0) == int32(0x80) {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
iCode = iCode<<libc.Int32FromInt32(6) + libc.Uint32FromInt32(libc.Int32FromInt32(0x3f)&libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1))))
|
|
}
|
|
if iCode < uint32(0x80) || iCode&uint32(0xFFFFF800) == uint32(0xD800) || iCode&uint32(0xFFFFFFFE) == uint32(0xFFFE) {
|
|
iCode = uint32(0xFFFD)
|
|
}
|
|
}
|
|
if (*TTrigramTokenizer)(unsafe.Pointer(p)).FbFold != 0 {
|
|
iCode = libc.Uint32FromInt32(_sqlite3Fts5UnicodeFold(tls, libc.Int32FromUint32(iCode), (*TTrigramTokenizer)(unsafe.Pointer(p)).FiFoldParam))
|
|
}
|
|
}
|
|
/* Pass the current trigram back to fts5 */
|
|
rc = (*(*func(*libc.TLS, uintptr, int32, uintptr, int32, int32, int32) int32)(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xToken})))(tls, pCtx, 0, bp, int32(int64(zOut)-t__predefined_ptrdiff_t(bp)), aStart[0], iNext)
|
|
if iCode == uint32(0) || rc != SQLITE_OK {
|
|
break
|
|
}
|
|
/* Remove the first character from buffer aBuf[]. Append the character
|
|
** with codepoint iCode. */
|
|
z1 = bp
|
|
v1 = z1
|
|
z1 = z1 + 1
|
|
if libc.Int32FromUint8(uint8(**(**uint8)(__ccgo_up(v1)))) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(uint8(**(**uint8)(__ccgo_up(z1))))&int32(0xc0) == int32(0x80) {
|
|
z1 = z1 + 1
|
|
}
|
|
}
|
|
libc.Xmemmove(tls, bp, z1, libc.Uint64FromInt64(int64(zOut)-int64(z1)))
|
|
zOut = zOut - uintptr(int64(z1)-t__predefined_ptrdiff_t(bp))
|
|
if iCode < uint32(0x00080) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(iCode & libc.Uint32FromInt32(0xFF))
|
|
} else {
|
|
if iCode < uint32(0x00800) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xC0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x1F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
if iCode < uint32(0x10000) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xE0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x0F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xF0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(18)&libc.Uint32FromInt32(0x07))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
}
|
|
}
|
|
}
|
|
/* Update the aStart[] array */
|
|
aStart[0] = aStart[int32(1)]
|
|
aStart[int32(1)] = aStart[int32(2)]
|
|
aStart[int32(2)] = iNext
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func _fts5UnicodeTokenize(tls *libc.TLS, pTokenizer uintptr, pCtx uintptr, iUnused int32, pText uintptr, nText int32, __ccgo_fp_xToken uintptr) (r int32) {
|
|
var a, aFold, p, pEnd, zCsr, zOut, zTerm, v3 uintptr
|
|
var iCode Tu32
|
|
var ie, is, nFold, rc, v7 int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _ = a, aFold, iCode, ie, is, nFold, p, pEnd, rc, zCsr, zOut, zTerm, v3, v7
|
|
p = pTokenizer
|
|
rc = SQLITE_OK
|
|
a = p
|
|
zTerm = pText + uintptr(nText)
|
|
zCsr = pText
|
|
/* Output buffer */
|
|
aFold = (*TUnicode61Tokenizer)(unsafe.Pointer(p)).FaFold
|
|
nFold = (*TUnicode61Tokenizer)(unsafe.Pointer(p)).FnFold
|
|
pEnd = aFold + uintptr(nFold-int32(6))
|
|
_ = iUnused
|
|
/* Each iteration of this loop gobbles up a contiguous run of separators,
|
|
** then the next token. */
|
|
_2:
|
|
;
|
|
if !(rc == SQLITE_OK) {
|
|
goto _1
|
|
} /* non-ASCII codepoint read from input */
|
|
zOut = aFold
|
|
/* Skip any separator characters. */
|
|
for int32(1) != 0 {
|
|
if zCsr >= zTerm {
|
|
goto tokenize_done
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zCsr)))&int32(0x80) != 0 {
|
|
/* A character outside of the ascii range. Skip past it if it is
|
|
** a separator character. Or break out of the loop if it is not. */
|
|
is = int32(int64(zCsr) - int64(pText))
|
|
v3 = zCsr
|
|
zCsr = zCsr + 1
|
|
iCode = uint32(**(**uint8)(__ccgo_up(v3)))
|
|
if iCode >= uint32(0xc0) {
|
|
iCode = uint32(_sqlite3Utf8Trans1[iCode-uint32(0xc0)])
|
|
for zCsr < zTerm && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zCsr)))&int32(0xc0) == int32(0x80) {
|
|
v3 = zCsr
|
|
zCsr = zCsr + 1
|
|
iCode = iCode<<libc.Int32FromInt32(6) + libc.Uint32FromInt32(libc.Int32FromInt32(0x3f)&libc.Int32FromUint8(**(**uint8)(__ccgo_up(v3))))
|
|
}
|
|
if iCode < uint32(0x80) || iCode&uint32(0xFFFFF800) == uint32(0xD800) || iCode&uint32(0xFFFFFFFE) == uint32(0xFFFE) {
|
|
iCode = uint32(0xFFFD)
|
|
}
|
|
}
|
|
if _fts5UnicodeIsAlnum(tls, p, libc.Int32FromUint32(iCode)) != 0 {
|
|
goto non_ascii_tokenchar
|
|
}
|
|
} else {
|
|
if **(**uint8)(__ccgo_up(a + uintptr(**(**uint8)(__ccgo_up(zCsr))))) != 0 {
|
|
is = int32(int64(zCsr) - int64(pText))
|
|
goto ascii_tokenchar
|
|
}
|
|
zCsr = zCsr + 1
|
|
}
|
|
}
|
|
/* Run through the tokenchars. Fold them into the output buffer along
|
|
** the way. */
|
|
_6:
|
|
;
|
|
if !(zCsr < zTerm) {
|
|
goto _5
|
|
}
|
|
/* Grow the output buffer so that there is sufficient space to fit the
|
|
** largest possible utf-8 character. */
|
|
if zOut > pEnd {
|
|
aFold = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(int64(nFold)*int64(2)))
|
|
if aFold == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
goto tokenize_done
|
|
}
|
|
zOut = aFold + uintptr(int64(zOut)-int64((*TUnicode61Tokenizer)(unsafe.Pointer(p)).FaFold))
|
|
libc.Xmemcpy(tls, aFold, (*TUnicode61Tokenizer)(unsafe.Pointer(p)).FaFold, libc.Uint64FromInt32(nFold))
|
|
Xsqlite3_free(tls, (*TUnicode61Tokenizer)(unsafe.Pointer(p)).FaFold)
|
|
(*TUnicode61Tokenizer)(unsafe.Pointer(p)).FaFold = aFold
|
|
v7 = nFold * libc.Int32FromInt32(2)
|
|
nFold = v7
|
|
(*TUnicode61Tokenizer)(unsafe.Pointer(p)).FnFold = v7
|
|
pEnd = aFold + uintptr(nFold-int32(6))
|
|
}
|
|
if !(libc.Int32FromUint8(**(**uint8)(__ccgo_up(zCsr)))&int32(0x80) != 0) {
|
|
goto _8
|
|
}
|
|
/* An non-ascii-range character. Fold it into the output buffer if
|
|
** it is a token character, or break out of the loop if it is not. */
|
|
v3 = zCsr
|
|
zCsr = zCsr + 1
|
|
iCode = uint32(**(**uint8)(__ccgo_up(v3)))
|
|
if iCode >= uint32(0xc0) {
|
|
iCode = uint32(_sqlite3Utf8Trans1[iCode-uint32(0xc0)])
|
|
for zCsr < zTerm && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zCsr)))&int32(0xc0) == int32(0x80) {
|
|
v3 = zCsr
|
|
zCsr = zCsr + 1
|
|
iCode = iCode<<libc.Int32FromInt32(6) + libc.Uint32FromInt32(libc.Int32FromInt32(0x3f)&libc.Int32FromUint8(**(**uint8)(__ccgo_up(v3))))
|
|
}
|
|
if iCode < uint32(0x80) || iCode&uint32(0xFFFFF800) == uint32(0xD800) || iCode&uint32(0xFFFFFFFE) == uint32(0xFFFE) {
|
|
iCode = uint32(0xFFFD)
|
|
}
|
|
}
|
|
if !(_fts5UnicodeIsAlnum(tls, p, libc.Int32FromUint32(iCode)) != 0 || _sqlite3Fts5UnicodeIsdiacritic(tls, libc.Int32FromUint32(iCode)) != 0) {
|
|
goto _12
|
|
}
|
|
goto non_ascii_tokenchar
|
|
non_ascii_tokenchar:
|
|
;
|
|
iCode = libc.Uint32FromInt32(_sqlite3Fts5UnicodeFold(tls, libc.Int32FromUint32(iCode), (*TUnicode61Tokenizer)(unsafe.Pointer(p)).FeRemoveDiacritic))
|
|
if iCode != 0 {
|
|
if iCode < uint32(0x00080) {
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = uint8(iCode & libc.Uint32FromInt32(0xFF))
|
|
} else {
|
|
if iCode < uint32(0x00800) {
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0xC0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x1F))))
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
if iCode < uint32(0x10000) {
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0xE0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x0F))))
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0xF0) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(18)&libc.Uint32FromInt32(0x07))))
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x3F))))
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(iCode&libc.Uint32FromInt32(0x3F))))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto _13
|
|
_12:
|
|
;
|
|
goto _5
|
|
_13:
|
|
;
|
|
goto _9
|
|
_8:
|
|
;
|
|
if !(libc.Int32FromUint8(**(**uint8)(__ccgo_up(a + uintptr(**(**uint8)(__ccgo_up(zCsr)))))) == 0) {
|
|
goto _24
|
|
}
|
|
/* An ascii-range separator character. End of token. */
|
|
goto _5
|
|
goto _25
|
|
_24:
|
|
;
|
|
goto ascii_tokenchar
|
|
ascii_tokenchar:
|
|
;
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zCsr))) >= int32('A') && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zCsr))) <= int32('Z') {
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = libc.Uint8FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(zCsr))) + int32(32))
|
|
} else {
|
|
v3 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v3)) = uint8(**(**uint8)(__ccgo_up(zCsr)))
|
|
}
|
|
zCsr = zCsr + 1
|
|
_25:
|
|
;
|
|
_9:
|
|
;
|
|
ie = int32(int64(zCsr) - int64(pText))
|
|
goto _6
|
|
_5:
|
|
;
|
|
/* Invoke the token callback */
|
|
rc = (*(*func(*libc.TLS, uintptr, int32, uintptr, int32, int32, int32) int32)(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xToken})))(tls, pCtx, 0, aFold, int32(int64(zOut)-int64(aFold)), is, ie)
|
|
goto _2
|
|
_1:
|
|
;
|
|
goto tokenize_done
|
|
tokenize_done:
|
|
;
|
|
if rc == int32(SQLITE_DONE) {
|
|
rc = SQLITE_OK
|
|
}
|
|
return rc
|
|
}
|
|
|
|
/**************************************************************************
|
|
** Start of porter stemmer implementation.
|
|
*/
|
|
|
|
/* Any tokens larger than this (in bytes) are passed through without
|
|
** stemming. */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the input is a well-formed JSON array of coordinates with at least
|
|
// ** four coordinates and where each coordinate is itself a two-value array,
|
|
// ** then convert the JSON into a GeoPoly object and return a pointer to
|
|
// ** that object.
|
|
// **
|
|
// ** If any error occurs, return NULL.
|
|
// */
|
|
func _geopolyParseJson(tls *libc.TLS, z uintptr, pRc uintptr) (r uintptr) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var aNew, pOut, v1 uintptr
|
|
var c uint8
|
|
var ii, rc int32
|
|
var v2 bool
|
|
var _ /* s at bp+0 */ TGeoParse
|
|
var _ /* x at bp+32 */ int32
|
|
_, _, _, _, _, _, _ = aNew, c, ii, pOut, rc, v1, v2
|
|
rc = SQLITE_OK
|
|
libc.Xmemset(tls, bp, 0, uint64(32))
|
|
(**(**TGeoParse)(__ccgo_up(bp))).Fz = z
|
|
if libc.Int32FromUint8(_geopolySkipSpace(tls, bp)) == int32('[') {
|
|
(**(**TGeoParse)(__ccgo_up(bp))).Fz = (**(**TGeoParse)(__ccgo_up(bp))).Fz + 1
|
|
for libc.Int32FromUint8(_geopolySkipSpace(tls, bp)) == int32('[') {
|
|
ii = 0
|
|
(**(**TGeoParse)(__ccgo_up(bp))).Fz = (**(**TGeoParse)(__ccgo_up(bp))).Fz + 1
|
|
if (**(**TGeoParse)(__ccgo_up(bp))).FnVertex >= (**(**TGeoParse)(__ccgo_up(bp))).FnAlloc {
|
|
(**(**TGeoParse)(__ccgo_up(bp))).FnAlloc = (**(**TGeoParse)(__ccgo_up(bp))).FnAlloc*int32(2) + int32(16)
|
|
aNew = Xsqlite3_realloc64(tls, (**(**TGeoParse)(__ccgo_up(bp))).Fa, uint64(libc.Uint64FromInt32((**(**TGeoParse)(__ccgo_up(bp))).FnAlloc)*uint64(4)*uint64(2)))
|
|
if aNew == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
(**(**TGeoParse)(__ccgo_up(bp))).FnErr = (**(**TGeoParse)(__ccgo_up(bp))).FnErr + 1
|
|
break
|
|
}
|
|
(**(**TGeoParse)(__ccgo_up(bp))).Fa = aNew
|
|
}
|
|
for {
|
|
if ii <= int32(1) {
|
|
v1 = (**(**TGeoParse)(__ccgo_up(bp))).Fa + uintptr((**(**TGeoParse)(__ccgo_up(bp))).FnVertex*int32(2)+ii)*4
|
|
} else {
|
|
v1 = uintptr(0)
|
|
}
|
|
if !(_geopolyParseNumber(tls, bp, v1) != 0) {
|
|
break
|
|
}
|
|
ii = ii + 1
|
|
if ii == int32(2) {
|
|
(**(**TGeoParse)(__ccgo_up(bp))).FnVertex = (**(**TGeoParse)(__ccgo_up(bp))).FnVertex + 1
|
|
}
|
|
c = _geopolySkipSpace(tls, bp)
|
|
(**(**TGeoParse)(__ccgo_up(bp))).Fz = (**(**TGeoParse)(__ccgo_up(bp))).Fz + 1
|
|
if libc.Int32FromUint8(c) == int32(',') {
|
|
continue
|
|
}
|
|
if libc.Int32FromUint8(c) == int32(']') && ii >= int32(2) {
|
|
break
|
|
}
|
|
(**(**TGeoParse)(__ccgo_up(bp))).FnErr = (**(**TGeoParse)(__ccgo_up(bp))).FnErr + 1
|
|
rc = int32(SQLITE_ERROR)
|
|
goto parse_json_err
|
|
}
|
|
if libc.Int32FromUint8(_geopolySkipSpace(tls, bp)) == int32(',') {
|
|
(**(**TGeoParse)(__ccgo_up(bp))).Fz = (**(**TGeoParse)(__ccgo_up(bp))).Fz + 1
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
if v2 = libc.Int32FromUint8(_geopolySkipSpace(tls, bp)) == int32(']') && (**(**TGeoParse)(__ccgo_up(bp))).FnVertex >= int32(4) && **(**TGeoCoord)(__ccgo_up((**(**TGeoParse)(__ccgo_up(bp))).Fa)) == **(**TGeoCoord)(__ccgo_up((**(**TGeoParse)(__ccgo_up(bp))).Fa + uintptr((**(**TGeoParse)(__ccgo_up(bp))).FnVertex*int32(2)-int32(2))*4)) && **(**TGeoCoord)(__ccgo_up((**(**TGeoParse)(__ccgo_up(bp))).Fa + 1*4)) == **(**TGeoCoord)(__ccgo_up((**(**TGeoParse)(__ccgo_up(bp))).Fa + uintptr((**(**TGeoParse)(__ccgo_up(bp))).FnVertex*int32(2)-int32(1))*4)); v2 {
|
|
(**(**TGeoParse)(__ccgo_up(bp))).Fz = (**(**TGeoParse)(__ccgo_up(bp))).Fz + 1
|
|
}
|
|
if v2 && libc.Int32FromUint8(_geopolySkipSpace(tls, bp)) == libc.Int32FromInt32(0) {
|
|
**(**int32)(__ccgo_up(bp + 32)) = int32(1)
|
|
(**(**TGeoParse)(__ccgo_up(bp))).FnVertex = (**(**TGeoParse)(__ccgo_up(bp))).FnVertex - 1 /* Remove the redundant vertex at the end */
|
|
pOut = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(40)+uint64(libc.Uint64FromInt64(4)*libc.Uint64FromInt32(2))*libc.Uint64FromInt64(int64((**(**TGeoParse)(__ccgo_up(bp))).FnVertex)-libc.Int64FromInt32(4)))
|
|
**(**int32)(__ccgo_up(bp + 32)) = int32(1)
|
|
if pOut == uintptr(0) {
|
|
goto parse_json_err
|
|
}
|
|
(*TGeoPoly)(unsafe.Pointer(pOut)).FnVertex = (**(**TGeoParse)(__ccgo_up(bp))).FnVertex
|
|
libc.Xmemcpy(tls, pOut+8, (**(**TGeoParse)(__ccgo_up(bp))).Fa, libc.Uint64FromInt32((**(**TGeoParse)(__ccgo_up(bp))).FnVertex*int32(2))*uint64(4))
|
|
**(**uint8)(__ccgo_up(pOut + 4)) = **(**uint8)(__ccgo_up(bp + 32))
|
|
**(**uint8)(__ccgo_up(pOut + 4 + 1)) = libc.Uint8FromInt32((**(**TGeoParse)(__ccgo_up(bp))).FnVertex >> int32(16) & int32(0xff))
|
|
**(**uint8)(__ccgo_up(pOut + 4 + 2)) = libc.Uint8FromInt32((**(**TGeoParse)(__ccgo_up(bp))).FnVertex >> int32(8) & int32(0xff))
|
|
**(**uint8)(__ccgo_up(pOut + 4 + 3)) = libc.Uint8FromInt32((**(**TGeoParse)(__ccgo_up(bp))).FnVertex & int32(0xff))
|
|
Xsqlite3_free(tls, (**(**TGeoParse)(__ccgo_up(bp))).Fa)
|
|
if pRc != 0 {
|
|
**(**int32)(__ccgo_up(pRc)) = SQLITE_OK
|
|
}
|
|
return pOut
|
|
} else {
|
|
(**(**TGeoParse)(__ccgo_up(bp))).FnErr = (**(**TGeoParse)(__ccgo_up(bp))).FnErr + 1
|
|
rc = int32(SQLITE_ERROR)
|
|
}
|
|
}
|
|
goto parse_json_err
|
|
parse_json_err:
|
|
;
|
|
if pRc != 0 {
|
|
**(**int32)(__ccgo_up(pRc)) = rc
|
|
}
|
|
Xsqlite3_free(tls, (**(**TGeoParse)(__ccgo_up(bp))).Fa)
|
|
return uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Interpret the given string as a safety level. Return 0 for OFF,
|
|
// ** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
|
|
// ** unrecognized string argument. The FULL and EXTRA option is disallowed
|
|
// ** if the omitFull parameter it 1.
|
|
// **
|
|
// ** Note that the values returned are one less that the values that
|
|
// ** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
|
|
// ** to support legacy SQL code. The safety level used to be boolean
|
|
// ** and older scripts may have used numbers 0 for OFF and 1 for ON.
|
|
// */
|
|
func _getSafetyLevel(tls *libc.TLS, z uintptr, omitFull int32, dflt Tu8) (r Tu8) {
|
|
var i, n int32
|
|
_, _ = i, n
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(z)))])&int32(0x04) != 0 {
|
|
return libc.Uint8FromInt32(_sqlite3Atoi(tls, z))
|
|
}
|
|
n = _sqlite3Strlen30(tls, z)
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint64(libc.Uint64FromInt64(8)/libc.Uint64FromInt64(1))) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(_iLength[i]) == n && Xsqlite3_strnicmp(tls, uintptr(unsafe.Pointer(&_zText))+uintptr(_iOffset[i]), z, n) == 0 && (!(omitFull != 0) || libc.Int32FromUint8(_iValue[i]) <= int32(1)) {
|
|
return _iValue[i]
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return dflt
|
|
}
|
|
|
|
func _groupConcatStep(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var db, pGCC, pnsl, zSep, zVal uintptr
|
|
var firstTerm, i, nA, nSep, nVal, v1 int32
|
|
_, _, _, _, _, _, _, _, _, _, _ = db, firstTerm, i, nA, nSep, nVal, pGCC, pnsl, zSep, zVal, v1
|
|
if Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv))) == int32(SQLITE_NULL) {
|
|
return
|
|
}
|
|
pGCC = Xsqlite3_aggregate_context(tls, context, int32(48))
|
|
if pGCC != 0 {
|
|
db = Xsqlite3_context_db_handle(tls, context)
|
|
firstTerm = libc.BoolInt32((*TGroupConcatCtx)(unsafe.Pointer(pGCC)).Fstr.FmxAlloc == uint32(0))
|
|
(*TGroupConcatCtx)(unsafe.Pointer(pGCC)).Fstr.FmxAlloc = libc.Uint32FromInt32(**(**int32)(__ccgo_up(db + 136)))
|
|
if argc == int32(1) {
|
|
if !(firstTerm != 0) {
|
|
Xsqlite3_str_appendchar(tls, pGCC, int32(1), uint8(','))
|
|
} else {
|
|
(*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnFirstSepLength = int32(1)
|
|
}
|
|
} else {
|
|
if !(firstTerm != 0) {
|
|
zSep = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
nSep = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
if zSep != 0 {
|
|
Xsqlite3_str_append(tls, pGCC, zSep, nSep)
|
|
} else {
|
|
nSep = 0
|
|
}
|
|
if nSep != (*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnFirstSepLength || (*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FpnSepLengths != uintptr(0) {
|
|
pnsl = (*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FpnSepLengths
|
|
if pnsl == uintptr(0) {
|
|
/* First separator length variation seen, start tracking them. */
|
|
pnsl = Xsqlite3_malloc64(tls, uint64(libc.Uint64FromInt32((*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnAccum+libc.Int32FromInt32(1))*uint64(4)))
|
|
if pnsl != uintptr(0) {
|
|
i = 0
|
|
nA = (*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnAccum - int32(1)
|
|
for i < nA {
|
|
v1 = i
|
|
i = i + 1
|
|
**(**int32)(__ccgo_up(pnsl + uintptr(v1)*4)) = (*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnFirstSepLength
|
|
}
|
|
}
|
|
} else {
|
|
pnsl = Xsqlite3_realloc64(tls, pnsl, uint64(libc.Uint64FromInt32((*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnAccum)*uint64(4)))
|
|
}
|
|
if pnsl != uintptr(0) {
|
|
if (*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnAccum > 0 {
|
|
**(**int32)(__ccgo_up(pnsl + uintptr((*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnAccum-int32(1))*4)) = nSep
|
|
}
|
|
(*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FpnSepLengths = pnsl
|
|
} else {
|
|
_sqlite3StrAccumSetError(tls, pGCC, uint8(SQLITE_NOMEM))
|
|
}
|
|
}
|
|
} else {
|
|
(*TGroupConcatCtx)(unsafe.Pointer(pGCC)).FnFirstSepLength = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
}
|
|
}
|
|
**(**int32)(__ccgo_up(pGCC + 32)) += int32(1)
|
|
zVal = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
nVal = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if zVal != 0 {
|
|
Xsqlite3_str_append(tls, pGCC, zVal, nVal)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The hex() function. Interpret the argument as a blob. Return
|
|
// ** a hexadecimal rendering as text.
|
|
// */
|
|
func _hexFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var c uint8
|
|
var i, n int32
|
|
var pBlob, z, zHex, v1 uintptr
|
|
_, _, _, _, _, _, _ = c, i, n, pBlob, z, zHex, v1
|
|
_ = argc
|
|
pBlob = Xsqlite3_value_blob(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
n = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
/* No encoding change */
|
|
v1 = _contextMalloc(tls, context, int64(n)*int64(2)+int64(1))
|
|
zHex = v1
|
|
z = v1
|
|
if zHex != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < n) {
|
|
break
|
|
}
|
|
c = **(**uint8)(__ccgo_up(pBlob))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = _hexdigits[libc.Int32FromUint8(c)>>int32(4)&int32(0xf)]
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = _hexdigits[libc.Int32FromUint8(c)&int32(0xf)]
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
pBlob = pBlob + 1
|
|
}
|
|
**(**uint8)(__ccgo_up(z)) = uint8(0)
|
|
Xsqlite3_result_text64(tls, context, zHex, libc.Uint64FromInt64(int64(z)-int64(zHex)), __ccgo_fp(Xsqlite3_free), uint8(SQLITE_UTF8_ZT))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Term pTerm is guaranteed to be a WO_IN term. It may be a component term
|
|
// ** of a vector IN expression of the form "(x, y, ...) IN (SELECT ...)".
|
|
// ** This function checks to see if the term is compatible with an index
|
|
// ** column with affinity idxaff (one of the SQLITE_AFF_XYZ values). If so,
|
|
// ** it returns a pointer to the name of the collation sequence (e.g. "BINARY"
|
|
// ** or "NOCASE") used by the comparison in pTerm. If it is not compatible
|
|
// ** with affinity idxaff, NULL is returned.
|
|
// */
|
|
func _indexInAffinityOk(tls *libc.TLS, pParse uintptr, pTerm uintptr, idxaff Tu8) (r uintptr) {
|
|
bp := tls.Alloc(80)
|
|
defer tls.Free(80)
|
|
var iField int32
|
|
var pRet, pX, v1 uintptr
|
|
var _ /* inexpr at bp+0 */ TExpr
|
|
_, _, _, _ = iField, pRet, pX, v1
|
|
pX = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
if _sqlite3ExprIsVector(tls, (*TExpr)(unsafe.Pointer(pX)).FpLeft) != 0 {
|
|
iField = (*(*struct {
|
|
FleftColumn int32
|
|
FiField int32
|
|
})(unsafe.Pointer(pTerm + 32))).FiField - int32(1)
|
|
(**(**TExpr)(__ccgo_up(bp))).Fflags = uint32(0)
|
|
(**(**TExpr)(__ccgo_up(bp))).Fop = uint8(TK_EQ)
|
|
(**(**TExpr)(__ccgo_up(bp))).FpLeft = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pX)).FpLeft + 32)) + 8 + uintptr(iField)*32))).FpExpr
|
|
(**(**TExpr)(__ccgo_up(bp))).FpRight = (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pX + 32)))).FpEList + 8 + uintptr(iField)*32))).FpExpr
|
|
pX = bp
|
|
}
|
|
if _sqlite3IndexAffinityOk(tls, pX, idxaff) != 0 {
|
|
pRet = _sqlite3ExprCompareCollSeq(tls, pParse, pX)
|
|
if pRet != 0 {
|
|
v1 = (*TCollSeq)(unsafe.Pointer(pRet)).FzName
|
|
} else {
|
|
v1 = uintptr(unsafe.Pointer(&_sqlite3StrBINARY))
|
|
}
|
|
return v1
|
|
}
|
|
return uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Process time function arguments. argv[0] is a date-time stamp.
|
|
// ** argv[1] and following are modifiers. Parse them all and write
|
|
// ** the resulting time into the DateTime structure p. Return 0
|
|
// ** on success and 1 if there are any errors.
|
|
// **
|
|
// ** If there are zero parameters (if even argv[0] is undefined)
|
|
// ** then assume a default value of "now" for argv[0].
|
|
// */
|
|
func _isDate(tls *libc.TLS, context uintptr, argc int32, argv uintptr, p uintptr) (r int32) {
|
|
var eType, i, n, v1 int32
|
|
var z uintptr
|
|
_, _, _, _, _ = eType, i, n, z, v1
|
|
libc.Xmemset(tls, p, 0, uint64(48))
|
|
if argc == 0 {
|
|
if !(_sqlite3NotPureFunc(tls, context) != 0) {
|
|
return int32(1)
|
|
}
|
|
return _setDateTimeToCurrent(tls, context, p)
|
|
}
|
|
v1 = Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
eType = v1
|
|
if v1 == int32(SQLITE_FLOAT) || eType == int32(SQLITE_INTEGER) {
|
|
_setRawDateNumber(tls, p, Xsqlite3_value_double(tls, **(**uintptr)(__ccgo_up(argv))))
|
|
} else {
|
|
z = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if !(z != 0) || _parseDateOrTime(tls, context, z, p) != 0 {
|
|
return int32(1)
|
|
}
|
|
}
|
|
i = int32(1)
|
|
for {
|
|
if !(i < argc) {
|
|
break
|
|
}
|
|
z = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8)))
|
|
n = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8)))
|
|
if z == uintptr(0) || _parseModifier(tls, context, z, n, p, i) != 0 {
|
|
return int32(1)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_computeJD(tls, p)
|
|
if int32(uint32(*(*uint8)(unsafe.Pointer(p + 44))&0x2>>1)) != 0 || !(_validJulianDay(tls, (*TDateTime)(unsafe.Pointer(p)).FiJD) != 0) {
|
|
return int32(1)
|
|
}
|
|
if argc == int32(1) && (*TDateTime)(unsafe.Pointer(p)).FvalidYMD != 0 && (*TDateTime)(unsafe.Pointer(p)).FD > int32(28) {
|
|
/* Make sure a YYYY-MM-DD is normalized.
|
|
** Example: 2023-02-31 -> 2023-03-03 */
|
|
(*TDateTime)(unsafe.Pointer(p)).FvalidYMD = uint8(0)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
/*
|
|
** The following routines implement the various date and time functions
|
|
** of SQLite.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if the given expression is a LIKE or GLOB operator that
|
|
// ** can be optimized using inequality constraints. Return TRUE if it is
|
|
// ** so and false if not.
|
|
// **
|
|
// ** In order for the operator to be optimizible, the RHS must be a string
|
|
// ** literal that does not begin with a wildcard. The LHS must be a column
|
|
// ** that may only be NULL, a string, or a BLOB, never a number. (This means
|
|
// ** that virtual tables cannot participate in the LIKE optimization.) The
|
|
// ** collating sequence for the column on the LHS must be appropriate for
|
|
// ** the operator.
|
|
// */
|
|
func _isLikeOrGlob(tls *libc.TLS, pParse uintptr, pExpr uintptr, ppPrefix uintptr, pisComplete uintptr, pnoCase uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var c, v1 Tu8
|
|
var cnt, iCol, iFrom, iTo, isNum, op, r1, rc, v3 int32
|
|
var db, pLeft, pList, pPrefix, pReprepare, pRight, pVal, v, z, zNew uintptr
|
|
var _ /* rDummy at bp+16 */ float64
|
|
var _ /* wc at bp+0 */ [4]Tu8
|
|
var _ /* z2 at bp+8 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = c, cnt, db, iCol, iFrom, iTo, isNum, op, pLeft, pList, pPrefix, pReprepare, pRight, pVal, r1, rc, v, z, zNew, v1, v3
|
|
z = uintptr(0) /* Wildcard characters */
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* Database connection */
|
|
pVal = uintptr(0) /* Result code to return */
|
|
if !(_sqlite3IsLikeFunction(tls, db, pExpr, pnoCase, bp) != 0) {
|
|
return 0
|
|
}
|
|
pList = *(*uintptr)(unsafe.Pointer(pExpr + 32))
|
|
pLeft = (*(*TExprList_item)(unsafe.Pointer(pList + 8 + 1*32))).FpExpr
|
|
pRight = _sqlite3ExprSkipCollate(tls, (*(*TExprList_item)(unsafe.Pointer(pList + 8))).FpExpr)
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pRight)).Fop)
|
|
if op == int32(TK_VARIABLE) && (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_EnableQPSG) == uint64(0) {
|
|
pReprepare = (*TParse)(unsafe.Pointer(pParse)).FpReprepare
|
|
iCol = int32((*TExpr)(unsafe.Pointer(pRight)).FiColumn)
|
|
pVal = _sqlite3VdbeGetBoundValue(tls, pReprepare, iCol, uint8(SQLITE_AFF_BLOB))
|
|
if pVal != 0 && Xsqlite3_value_type(tls, pVal) == int32(SQLITE_TEXT) {
|
|
z = Xsqlite3_value_text(tls, pVal)
|
|
}
|
|
_sqlite3VdbeSetVarmask(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, iCol)
|
|
} else {
|
|
if op == int32(TK_STRING) {
|
|
z = *(*uintptr)(unsafe.Pointer(pRight + 8))
|
|
}
|
|
}
|
|
if z != 0 {
|
|
/* Count the number of prefix bytes prior to the first wildcard,
|
|
** U+fffd character, or malformed utf-8. If the underlying database
|
|
** has a UTF16LE encoding, then only consider ASCII characters. Note that
|
|
** the encoding of z[] is UTF8 - we are dealing with only UTF8 here in this
|
|
** code, but the database engine itself might be processing content using a
|
|
** different encoding. */
|
|
cnt = 0
|
|
for {
|
|
v1 = **(**Tu8)(__ccgo_up(z + uintptr(cnt)))
|
|
c = v1
|
|
if !(libc.Int32FromUint8(v1) != 0 && libc.Int32FromUint8(c) != libc.Int32FromUint8((**(**[4]Tu8)(__ccgo_up(bp)))[0]) && libc.Int32FromUint8(c) != libc.Int32FromUint8((**(**[4]Tu8)(__ccgo_up(bp)))[int32(1)]) && libc.Int32FromUint8(c) != libc.Int32FromUint8((**(**[4]Tu8)(__ccgo_up(bp)))[int32(2)])) {
|
|
break
|
|
}
|
|
cnt = cnt + 1
|
|
if libc.Int32FromUint8(c) == libc.Int32FromUint8((**(**[4]Tu8)(__ccgo_up(bp)))[int32(3)]) && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z + uintptr(cnt)))) > 0 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z + uintptr(cnt)))) < int32(0x80) {
|
|
cnt = cnt + 1
|
|
} else {
|
|
if libc.Int32FromUint8(c) >= int32(0x80) {
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = z + uintptr(cnt) - uintptr(1)
|
|
if libc.Int32FromUint8(c) == int32(0xff) || _sqlite3Utf8Read(tls, bp+8) == uint32(0xfffd) || libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).Fenc) == int32(SQLITE_UTF16LE) {
|
|
cnt = cnt - 1
|
|
break
|
|
} else {
|
|
cnt = int32(int64(**(**uintptr)(__ccgo_up(bp + 8))) - int64(z))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* The optimization is possible only if (1) the pattern does not begin
|
|
** with a wildcard and if (2) the non-wildcard prefix does not end with
|
|
** an (illegal 0xff) character, or (3) the pattern does not consist of
|
|
** a single escape character. The second condition is necessary so
|
|
** that we can increment the prefix key to find an upper bound for the
|
|
** range search. The third is because the caller assumes that the pattern
|
|
** consists of at least one character after all escapes have been
|
|
** removed. */
|
|
if (cnt > int32(1) || cnt > 0 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z))) != libc.Int32FromUint8((**(**[4]Tu8)(__ccgo_up(bp)))[int32(3)])) && int32(255) != libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z + uintptr(cnt-int32(1))))) {
|
|
/* A "complete" match if the pattern ends with "*" or "%" */
|
|
**(**int32)(__ccgo_up(pisComplete)) = libc.BoolInt32(libc.Int32FromUint8(c) == libc.Int32FromUint8((**(**[4]Tu8)(__ccgo_up(bp)))[0]) && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z + uintptr(cnt+int32(1))))) == 0 && libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).Fenc) != int32(SQLITE_UTF16LE))
|
|
/* Get the pattern prefix. Remove all escapes from the prefix. */
|
|
pPrefix = _sqlite3Expr(tls, db, int32(TK_STRING), z)
|
|
if pPrefix != 0 {
|
|
zNew = *(*uintptr)(unsafe.Pointer(pPrefix + 8))
|
|
**(**uint8)(__ccgo_up(zNew + uintptr(cnt))) = uint8(0)
|
|
v3 = libc.Int32FromInt32(0)
|
|
iTo = v3
|
|
iFrom = v3
|
|
for {
|
|
if !(iFrom < cnt) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNew + uintptr(iFrom)))) == libc.Int32FromUint8((**(**[4]Tu8)(__ccgo_up(bp)))[int32(3)]) {
|
|
iFrom = iFrom + 1
|
|
}
|
|
v3 = iTo
|
|
iTo = iTo + 1
|
|
**(**uint8)(__ccgo_up(zNew + uintptr(v3))) = **(**uint8)(__ccgo_up(zNew + uintptr(iFrom)))
|
|
goto _2
|
|
_2:
|
|
;
|
|
iFrom = iFrom + 1
|
|
}
|
|
**(**uint8)(__ccgo_up(zNew + uintptr(iTo))) = uint8(0)
|
|
/* If the LHS is not an ordinary column with TEXT affinity, then the
|
|
** pattern prefix boundaries (both the start and end boundaries) must
|
|
** not look like a number. Otherwise the pattern might be treated as
|
|
** a number, which will invalidate the LIKE optimization.
|
|
**
|
|
** Getting this right has been a persistent source of bugs in the
|
|
** LIKE optimization. See, for example:
|
|
** 2018-09-10 https://sqlite.org/src/info/c94369cae9b561b1
|
|
** 2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28
|
|
** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07
|
|
** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975
|
|
** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a
|
|
*/
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pLeft)).Fop) != int32(TK_COLUMN) || libc.Int32FromUint8(_sqlite3ExprAffinity(tls, pLeft)) != int32(SQLITE_AFF_TEXT) || (*TExpr)(unsafe.Pointer(pLeft)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)|libc.Int32FromInt32(EP_Subrtn)) == uint32(0) && *(*uintptr)(unsafe.Pointer(pLeft + 64)) != 0 && libc.Int32FromUint8((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pLeft + 64)))).FeTabType) == int32(TABTYP_VTAB) {
|
|
isNum = _sqlite3AtoF(tls, zNew, bp+16)
|
|
if isNum <= 0 {
|
|
if iTo == int32(1) && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNew))) == int32('-') {
|
|
isNum = +libc.Int32FromInt32(1)
|
|
} else {
|
|
**(**uint8)(__ccgo_up(zNew + uintptr(iTo-int32(1)))) = **(**uint8)(__ccgo_up(zNew + uintptr(iTo-int32(1)))) + 1
|
|
isNum = _sqlite3AtoF(tls, zNew, bp+16)
|
|
**(**uint8)(__ccgo_up(zNew + uintptr(iTo-int32(1)))) = **(**uint8)(__ccgo_up(zNew + uintptr(iTo-int32(1)))) - 1
|
|
}
|
|
}
|
|
if isNum > 0 {
|
|
_sqlite3ExprDelete(tls, db, pPrefix)
|
|
_sqlite3ValueFree(tls, pVal)
|
|
return 0
|
|
}
|
|
}
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppPrefix)) = pPrefix
|
|
/* If the RHS pattern is a bound parameter, make arrangements to
|
|
** reprepare the statement when that parameter is rebound */
|
|
if op == int32(TK_VARIABLE) {
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
_sqlite3VdbeSetVarmask(tls, v, int32((*TExpr)(unsafe.Pointer(pRight)).FiColumn))
|
|
if **(**int32)(__ccgo_up(pisComplete)) != 0 && **(**uint8)(__ccgo_up(*(*uintptr)(unsafe.Pointer(pRight + 8)) + 1)) != 0 {
|
|
/* If the rhs of the LIKE expression is a variable, and the current
|
|
** value of the variable means there is no need to invoke the LIKE
|
|
** function, then no OP_Variable will be added to the program.
|
|
** This causes problems for the sqlite3_bind_parameter_name()
|
|
** API. To work around them, add a dummy OP_Variable here.
|
|
*/
|
|
r1 = _sqlite3GetTempReg(tls, pParse)
|
|
_sqlite3ExprCodeTarget(tls, pParse, pRight, r1)
|
|
_sqlite3VdbeChangeP3(tls, v, _sqlite3VdbeCurrentAddr(tls, v)-int32(1), 0)
|
|
_sqlite3ReleaseTempReg(tls, pParse, r1)
|
|
}
|
|
}
|
|
} else {
|
|
z = uintptr(0)
|
|
}
|
|
}
|
|
rc = libc.BoolInt32(z != uintptr(0))
|
|
_sqlite3ValueFree(tls, pVal)
|
|
return rc
|
|
}
|
|
|
|
func _jsonAppendChar(tls *libc.TLS, p uintptr, c uint8) {
|
|
var v1 Tu64
|
|
var v2 uintptr
|
|
_, _ = v1, v2
|
|
if (*TJsonString)(unsafe.Pointer(p)).FnUsed >= (*TJsonString)(unsafe.Pointer(p)).FnAlloc {
|
|
_jsonAppendCharExpand(tls, p, c)
|
|
} else {
|
|
v2 = p + 24
|
|
v1 = *(*Tu64)(unsafe.Pointer(v2))
|
|
*(*Tu64)(unsafe.Pointer(v2)) = *(*Tu64)(unsafe.Pointer(v2)) + 1
|
|
**(**uint8)(__ccgo_up((*TJsonString)(unsafe.Pointer(p)).FzBuf + uintptr(v1))) = c
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Append a single character
|
|
// */
|
|
func _jsonAppendCharExpand(tls *libc.TLS, p uintptr, c uint8) {
|
|
var v1 Tu64
|
|
var v2 uintptr
|
|
_, _ = v1, v2
|
|
if _jsonStringGrow(tls, p, uint32(1)) != 0 {
|
|
return
|
|
}
|
|
v2 = p + 24
|
|
v1 = *(*Tu64)(unsafe.Pointer(v2))
|
|
*(*Tu64)(unsafe.Pointer(v2)) = *(*Tu64)(unsafe.Pointer(v2)) + 1
|
|
**(**uint8)(__ccgo_up((*TJsonString)(unsafe.Pointer(p)).FzBuf + uintptr(v1))) = c
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Append the N-byte string in zIn to the end of the JsonString string
|
|
// ** under construction. Enclose the string in double-quotes ("...") and
|
|
// ** escape any double-quotes or backslash characters contained within the
|
|
// ** string.
|
|
// **
|
|
// ** This routine is a high-runner. There is a measurable performance
|
|
// ** increase associated with unwinding the jsonIsOk[] loop.
|
|
// */
|
|
func _jsonAppendString(tls *libc.TLS, p uintptr, zIn uintptr, N Tu32) {
|
|
var c Tu8
|
|
var k Tu32
|
|
var z, v2 uintptr
|
|
var v1 Tu64
|
|
_, _, _, _, _ = c, k, z, v1, v2
|
|
z = zIn
|
|
if z == uintptr(0) {
|
|
return
|
|
}
|
|
if uint64(N)+(*TJsonString)(unsafe.Pointer(p)).FnUsed+uint64(2) >= (*TJsonString)(unsafe.Pointer(p)).FnAlloc && _jsonStringGrow(tls, p, N+uint32(2)) != 0 {
|
|
return
|
|
}
|
|
v2 = p + 24
|
|
v1 = *(*Tu64)(unsafe.Pointer(v2))
|
|
*(*Tu64)(unsafe.Pointer(v2)) = *(*Tu64)(unsafe.Pointer(v2)) + 1
|
|
**(**uint8)(__ccgo_up((*TJsonString)(unsafe.Pointer(p)).FzBuf + uintptr(v1))) = uint8('"')
|
|
for int32(1) != 0 {
|
|
k = uint32(0)
|
|
/* The following while() is the 4-way unwound equivalent of
|
|
**
|
|
** while( k<N && jsonIsOk[z[k]] ){ k++; }
|
|
*/
|
|
for int32(1) != 0 {
|
|
if k+uint32(3) >= N {
|
|
for k < N && _jsonIsOk[**(**Tu8)(__ccgo_up(z + uintptr(k)))] != 0 {
|
|
k = k + 1
|
|
}
|
|
break
|
|
}
|
|
if !(_jsonIsOk[**(**Tu8)(__ccgo_up(z + uintptr(k)))] != 0) {
|
|
break
|
|
}
|
|
if !(_jsonIsOk[**(**Tu8)(__ccgo_up(z + uintptr(k+uint32(1))))] != 0) {
|
|
k = k + uint32(1)
|
|
break
|
|
}
|
|
if !(_jsonIsOk[**(**Tu8)(__ccgo_up(z + uintptr(k+uint32(2))))] != 0) {
|
|
k = k + uint32(2)
|
|
break
|
|
}
|
|
if !(_jsonIsOk[**(**Tu8)(__ccgo_up(z + uintptr(k+uint32(3))))] != 0) {
|
|
k = k + uint32(3)
|
|
break
|
|
} else {
|
|
k = k + uint32(4)
|
|
}
|
|
}
|
|
if k >= N {
|
|
if k > uint32(0) {
|
|
libc.Xmemcpy(tls, (*TJsonString)(unsafe.Pointer(p)).FzBuf+uintptr((*TJsonString)(unsafe.Pointer(p)).FnUsed), z, uint64(k))
|
|
**(**Tu64)(__ccgo_up(p + 24)) += uint64(k)
|
|
}
|
|
break
|
|
}
|
|
if k > uint32(0) {
|
|
libc.Xmemcpy(tls, (*TJsonString)(unsafe.Pointer(p)).FzBuf+uintptr((*TJsonString)(unsafe.Pointer(p)).FnUsed), z, uint64(k))
|
|
**(**Tu64)(__ccgo_up(p + 24)) += uint64(k)
|
|
z = z + uintptr(k)
|
|
N = N - k
|
|
}
|
|
c = **(**Tu8)(__ccgo_up(z))
|
|
if libc.Int32FromUint8(c) == int32('"') || libc.Int32FromUint8(c) == int32('\\') {
|
|
if (*TJsonString)(unsafe.Pointer(p)).FnUsed+uint64(N)+uint64(3) > (*TJsonString)(unsafe.Pointer(p)).FnAlloc && _jsonStringGrow(tls, p, N+uint32(3)) != 0 {
|
|
return
|
|
}
|
|
v2 = p + 24
|
|
v1 = *(*Tu64)(unsafe.Pointer(v2))
|
|
*(*Tu64)(unsafe.Pointer(v2)) = *(*Tu64)(unsafe.Pointer(v2)) + 1
|
|
**(**uint8)(__ccgo_up((*TJsonString)(unsafe.Pointer(p)).FzBuf + uintptr(v1))) = uint8('\\')
|
|
v2 = p + 24
|
|
v1 = *(*Tu64)(unsafe.Pointer(v2))
|
|
*(*Tu64)(unsafe.Pointer(v2)) = *(*Tu64)(unsafe.Pointer(v2)) + 1
|
|
**(**uint8)(__ccgo_up((*TJsonString)(unsafe.Pointer(p)).FzBuf + uintptr(v1))) = c
|
|
} else {
|
|
if libc.Int32FromUint8(c) == int32('\'') {
|
|
v2 = p + 24
|
|
v1 = *(*Tu64)(unsafe.Pointer(v2))
|
|
*(*Tu64)(unsafe.Pointer(v2)) = *(*Tu64)(unsafe.Pointer(v2)) + 1
|
|
**(**uint8)(__ccgo_up((*TJsonString)(unsafe.Pointer(p)).FzBuf + uintptr(v1))) = c
|
|
} else {
|
|
if (*TJsonString)(unsafe.Pointer(p)).FnUsed+uint64(N)+uint64(7) > (*TJsonString)(unsafe.Pointer(p)).FnAlloc && _jsonStringGrow(tls, p, N+uint32(7)) != 0 {
|
|
return
|
|
}
|
|
_jsonAppendControlChar(tls, p, c)
|
|
}
|
|
}
|
|
z = z + 1
|
|
N = N - 1
|
|
}
|
|
v2 = p + 24
|
|
v1 = *(*Tu64)(unsafe.Pointer(v2))
|
|
*(*Tu64)(unsafe.Pointer(v2)) = *(*Tu64)(unsafe.Pointer(v2)) + 1
|
|
**(**uint8)(__ccgo_up((*TJsonString)(unsafe.Pointer(p)).FzBuf + uintptr(v1))) = uint8('"')
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the json_array(VALUE,...) function. Return a JSON
|
|
// ** array that contains all values given in arguments. Or if any argument
|
|
// ** is a BLOB, throw an error.
|
|
// */
|
|
func _jsonArrayFunc(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
|
bp := tls.Alloc(144)
|
|
defer tls.Free(144)
|
|
var i int32
|
|
var _ /* jx at bp+0 */ TJsonString
|
|
_ = i
|
|
_jsonStringInit(tls, bp, ctx)
|
|
_jsonAppendChar(tls, bp, uint8('['))
|
|
i = 0
|
|
for {
|
|
if !(i < argc) {
|
|
break
|
|
}
|
|
_jsonAppendSeparator(tls, bp)
|
|
_jsonAppendSqlValue(tls, bp, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8)))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_jsonAppendChar(tls, bp, uint8(']'))
|
|
_jsonReturnString(tls, bp, uintptr(0), uintptr(0))
|
|
Xsqlite3_result_subtype(tls, ctx, uint32(JSON_SUBTYPE))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /****************************************************************************
|
|
// ** Aggregate SQL function implementations
|
|
// ****************************************************************************/
|
|
// /*
|
|
// ** json_group_array(VALUE)
|
|
// **
|
|
// ** Return a JSON array composed of all values in the aggregate.
|
|
// */
|
|
func _jsonArrayStep(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
|
var pStr uintptr
|
|
_ = pStr
|
|
_ = argc
|
|
pStr = Xsqlite3_aggregate_context(tls, ctx, int32(136))
|
|
if pStr != 0 {
|
|
if (*TJsonString)(unsafe.Pointer(pStr)).FzBuf == uintptr(0) {
|
|
_jsonStringInit(tls, pStr, ctx)
|
|
_jsonAppendChar(tls, pStr, uint8('['))
|
|
} else {
|
|
if (*TJsonString)(unsafe.Pointer(pStr)).FnUsed > uint64(1) {
|
|
_jsonAppendChar(tls, pStr, uint8(','))
|
|
}
|
|
}
|
|
(*TJsonString)(unsafe.Pointer(pStr)).FpCtx = ctx
|
|
_jsonAppendSqlValue(tls, pStr, **(**uintptr)(__ccgo_up(argv)))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* This helper routine for jsonLookupStep() populates pIns with
|
|
// ** binary data that is to be inserted into pParse.
|
|
// **
|
|
// ** In the common case, pIns just points to pParse->aIns and pParse->nIns.
|
|
// ** But if the zPath of the original edit operation includes path elements
|
|
// ** that go deeper, additional substructure must be created.
|
|
// **
|
|
// ** For example:
|
|
// **
|
|
// ** json_insert('{}', '$.a.b.c', 123);
|
|
// **
|
|
// ** The search stops at '$.a' But additional substructure must be
|
|
// ** created for the ".b.c" part of the patch so that the final result
|
|
// ** is: {"a":{"b":{"c"::123}}}. This routine populates pIns with
|
|
// ** the binary equivalent of {"b":{"c":123}} so that it can be inserted.
|
|
// **
|
|
// ** The caller is responsible for resetting pIns when it has finished
|
|
// ** using the substructure.
|
|
// */
|
|
func _jsonCreateEditSubstructure(tls *libc.TLS, pParse uintptr, pIns uintptr, zTail uintptr) (r Tu32) {
|
|
var rc int32
|
|
var v1 uintptr
|
|
_, _ = rc, v1
|
|
libc.Xmemset(tls, pIns, 0, uint64(72))
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).Fdb = (*TJsonParse)(unsafe.Pointer(pParse)).Fdb
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zTail))) == 0 {
|
|
/* No substructure. Just insert what is given in pParse. */
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).FaBlob = (*TJsonParse)(unsafe.Pointer(pParse)).FaIns
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).FnBlob = (*TJsonParse)(unsafe.Pointer(pParse)).FnIns
|
|
rc = 0
|
|
} else {
|
|
/* Construct the binary substructure */
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).FnBlob = uint32(1)
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).FaBlob = uintptr(unsafe.Pointer(&_emptyObject)) + libc.BoolUintptr(libc.Int32FromUint8(**(**uint8)(__ccgo_up(zTail))) == int32('.'))
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).FeEdit = (*TJsonParse)(unsafe.Pointer(pParse)).FeEdit
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).FnIns = (*TJsonParse)(unsafe.Pointer(pParse)).FnIns
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).FaIns = (*TJsonParse)(unsafe.Pointer(pParse)).FaIns
|
|
(*TJsonParse)(unsafe.Pointer(pIns)).FiDepth = libc.Uint16FromInt32(libc.Int32FromUint16((*TJsonParse)(unsafe.Pointer(pParse)).FiDepth) + int32(1))
|
|
if libc.Int32FromUint16((*TJsonParse)(unsafe.Pointer(pIns)).FiDepth) >= int32(JSON_MAX_DEPTH) {
|
|
return uint32(JSON_LOOKUP_TOODEEP)
|
|
}
|
|
rc = libc.Int32FromUint32(_jsonLookupStep(tls, pIns, uint32(0), zTail, uint32(0)))
|
|
(*TJsonParse)(unsafe.Pointer(pParse)).FiDepth = (*TJsonParse)(unsafe.Pointer(pParse)).FiDepth - 1
|
|
v1 = pParse + 47
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) | libc.Int32FromUint8((*TJsonParse)(unsafe.Pointer(pIns)).Foom))
|
|
}
|
|
return libc.Uint32FromInt32(rc) /* Error code only */
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Return the value of a column */
|
|
func _jsonEachColumn(tls *libc.TLS, cur uintptr, ctx uintptr, iColumn int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var eType Tu8
|
|
var i, i1, i2, j, n, n1 Tu32
|
|
var nBase Tu64
|
|
var p uintptr
|
|
var _ /* x at bp+0 */ Ti64
|
|
_, _, _, _, _, _, _, _, _ = eType, i, i1, i2, j, n, n1, nBase, p
|
|
p = cur
|
|
switch iColumn {
|
|
case JEACH_KEY:
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent == uint32(0) {
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FnRoot == uint32(1) {
|
|
break
|
|
}
|
|
j = libc.Uint32FromInt32(_jsonEachPathLength(tls, p))
|
|
n = (*TJsonEachCursor)(unsafe.Pointer(p)).FnRoot - j
|
|
if n == uint32(0) {
|
|
break
|
|
} else {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf + uintptr(j)))) == int32('[') {
|
|
_sqlite3Atoi64(tls, (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf+uintptr(j+uint32(1)), bp, libc.Int32FromUint32(n-uint32(1)), uint8(SQLITE_UTF8))
|
|
Xsqlite3_result_int64(tls, ctx, **(**Ti64)(__ccgo_up(bp)))
|
|
} else {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf + uintptr(j+uint32(1))))) == int32('"') {
|
|
Xsqlite3_result_text(tls, ctx, (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf+uintptr(j+uint32(2)), libc.Int32FromUint32(n-uint32(3)), uintptr(-libc.Int32FromInt32(1)))
|
|
} else {
|
|
Xsqlite3_result_text(tls, ctx, (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf+uintptr(j+uint32(1)), libc.Int32FromUint32(n-uint32(1)), uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
}
|
|
}
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TJsonEachCursor)(unsafe.Pointer(p)).FeType) == int32(JSONB_OBJECT) {
|
|
_jsonReturnFromBlob(tls, p+192, (*TJsonEachCursor)(unsafe.Pointer(p)).Fi, ctx, int32(1))
|
|
} else {
|
|
Xsqlite3_result_int64(tls, ctx, (**(**TJsonParent)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FaParent + uintptr((*TJsonEachCursor)(unsafe.Pointer(p)).FnParent-uint32(1))*24))).FiKey)
|
|
}
|
|
case int32(JEACH_VALUE):
|
|
i = libc.Uint32FromInt32(_jsonSkipLabel(tls, p))
|
|
_jsonReturnFromBlob(tls, p+192, i, ctx, libc.Int32FromUint8((*TJsonEachCursor)(unsafe.Pointer(p)).FeMode))
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FaBlob + uintptr(i))))&int32(0x0f) >= int32(JSONB_ARRAY) {
|
|
Xsqlite3_result_subtype(tls, ctx, uint32(JSON_SUBTYPE))
|
|
}
|
|
case int32(JEACH_TYPE):
|
|
i1 = libc.Uint32FromInt32(_jsonSkipLabel(tls, p))
|
|
eType = libc.Uint8FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FaBlob + uintptr(i1)))) & int32(0x0f))
|
|
Xsqlite3_result_text(tls, ctx, _jsonbType[eType], -int32(1), libc.UintptrFromInt32(0))
|
|
case int32(JEACH_ATOM):
|
|
i2 = libc.Uint32FromInt32(_jsonSkipLabel(tls, p))
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FaBlob + uintptr(i2))))&int32(0x0f) < int32(JSONB_ARRAY) {
|
|
_jsonReturnFromBlob(tls, p+192, i2, ctx, int32(1))
|
|
}
|
|
case int32(JEACH_ID):
|
|
Xsqlite3_result_int64(tls, ctx, libc.Int64FromUint32((*TJsonEachCursor)(unsafe.Pointer(p)).Fi))
|
|
case int32(JEACH_PARENT):
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent > uint32(0) && (*TJsonEachCursor)(unsafe.Pointer(p)).FbRecursive != 0 {
|
|
Xsqlite3_result_int64(tls, ctx, libc.Int64FromUint32((**(**TJsonParent)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FaParent + uintptr((*TJsonEachCursor)(unsafe.Pointer(p)).FnParent-uint32(1))*24))).FiHead))
|
|
}
|
|
case int32(JEACH_FULLKEY):
|
|
nBase = (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FnUsed
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent != 0 {
|
|
_jsonAppendPathName(tls, p)
|
|
}
|
|
Xsqlite3_result_text64(tls, ctx, (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf, (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FnUsed, uintptr(-libc.Int32FromInt32(1)), uint8(SQLITE_UTF8))
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FnUsed = nBase
|
|
case int32(JEACH_PATH):
|
|
n1 = libc.Uint32FromInt32(_jsonEachPathLength(tls, p))
|
|
Xsqlite3_result_text64(tls, ctx, (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf, uint64(n1), uintptr(-libc.Int32FromInt32(1)), uint8(SQLITE_UTF8))
|
|
default:
|
|
Xsqlite3_result_text(tls, ctx, (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf, libc.Int32FromUint32((*TJsonEachCursor)(unsafe.Pointer(p)).FnRoot), libc.UintptrFromInt32(0))
|
|
case int32(JEACH_JSON):
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FzJson == uintptr(0) {
|
|
Xsqlite3_result_blob(tls, ctx, (*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FaBlob, libc.Int32FromUint32((*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FnBlob), uintptr(-libc.Int32FromInt32(1)))
|
|
} else {
|
|
Xsqlite3_result_text(tls, ctx, (*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FzJson, -int32(1), uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
break
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Length of the path for rowid==0 in bRecursive mode.
|
|
// */
|
|
func _jsonEachPathLength(tls *libc.TLS, p uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var cSaved uint8
|
|
var n, x Tu32
|
|
var z uintptr
|
|
var _ /* sz at bp+0 */ Tu32
|
|
_, _, _, _ = cSaved, n, x, z
|
|
n = uint32((*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FnUsed)
|
|
z = (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FzBuf
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FiRowid == uint32(0) && (*TJsonEachCursor)(unsafe.Pointer(p)).FbRecursive != 0 && n >= uint32(2) {
|
|
for n > uint32(1) {
|
|
n = n - 1
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(n)))) == int32('[') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(n)))) == int32('.') {
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
cSaved = **(**uint8)(__ccgo_up(z + uintptr(n)))
|
|
**(**uint8)(__ccgo_up(z + uintptr(n))) = uint8(0)
|
|
x = _jsonLookupStep(tls, p+192, uint32(0), z+uintptr(1), uint32(0))
|
|
**(**uint8)(__ccgo_up(z + uintptr(n))) = cSaved
|
|
if x >= uint32(JSON_LOOKUP_PATHERROR) {
|
|
continue
|
|
}
|
|
if x+_jsonbPayloadSize(tls, p+192, x, bp) == (*TJsonEachCursor)(unsafe.Pointer(p)).Fi {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return libc.Int32FromUint32(n)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** json_error_position(JSON)
|
|
// **
|
|
// ** If the argument is NULL, return NULL
|
|
// **
|
|
// ** If the argument is BLOB, do a full validity check and return non-zero
|
|
// ** if the check fails. The return value is the approximate 1-based offset
|
|
// ** to the byte of the element that contains the first error.
|
|
// **
|
|
// ** Otherwise interpret the argument is TEXT (even if it is numeric) and
|
|
// ** return the 1-based character position for where the parser first recognized
|
|
// ** that the input was not valid JSON, or return 0 if the input text looks
|
|
// ** ok. JSON-5 extensions are accepted.
|
|
// */
|
|
func _jsonErrorFunc(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
|
bp := tls.Alloc(80)
|
|
defer tls.Free(80)
|
|
var iErrPos Ti64
|
|
var k Tu32
|
|
var _ /* s at bp+0 */ TJsonParse
|
|
_, _ = iErrPos, k
|
|
iErrPos = 0
|
|
_ = argc
|
|
libc.Xmemset(tls, bp, 0, uint64(72))
|
|
(**(**TJsonParse)(__ccgo_up(bp))).Fdb = Xsqlite3_context_db_handle(tls, ctx)
|
|
if _jsonArgIsJsonb(tls, **(**uintptr)(__ccgo_up(argv)), bp) != 0 {
|
|
iErrPos = libc.Int64FromUint32(_jsonbValidityCheck(tls, bp, uint32(0), (**(**TJsonParse)(__ccgo_up(bp))).FnBlob, uint32(1)))
|
|
} else {
|
|
(**(**TJsonParse)(__ccgo_up(bp))).FzJson = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if (**(**TJsonParse)(__ccgo_up(bp))).FzJson == uintptr(0) {
|
|
return
|
|
} /* NULL input or OOM */
|
|
(**(**TJsonParse)(__ccgo_up(bp))).FnJson = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if _jsonConvertTextToBlob(tls, bp, uintptr(0)) != 0 {
|
|
if (**(**TJsonParse)(__ccgo_up(bp))).Foom != 0 {
|
|
iErrPos = int64(-int32(1))
|
|
} else {
|
|
/* Because s.oom is false */
|
|
k = uint32(0)
|
|
for {
|
|
if !(k < (**(**TJsonParse)(__ccgo_up(bp))).FiErr && **(**uint8)(__ccgo_up((**(**TJsonParse)(__ccgo_up(bp))).FzJson + uintptr(k))) != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up((**(**TJsonParse)(__ccgo_up(bp))).FzJson + uintptr(k))))&int32(0xc0) != int32(0x80) {
|
|
iErrPos = iErrPos + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
k = k + 1
|
|
}
|
|
iErrPos = iErrPos + 1
|
|
}
|
|
}
|
|
}
|
|
_jsonParseReset(tls, bp)
|
|
if iErrPos < 0 {
|
|
Xsqlite3_result_error_nomem(tls, ctx)
|
|
} else {
|
|
Xsqlite3_result_int64(tls, ctx, iErrPos)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This method works for both json_group_array() and json_group_object().
|
|
// ** It works by removing the first element of the group by searching forward
|
|
// ** to the first comma (",") that is not within a string and deleting all
|
|
// ** text through that comma.
|
|
// */
|
|
func _jsonGroupInverse(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
|
var c, v2 uint8
|
|
var i uint32
|
|
var inStr, nNest int32
|
|
var pStr, z uintptr
|
|
var v3 bool
|
|
_, _, _, _, _, _, _, _ = c, i, inStr, nNest, pStr, z, v2, v3
|
|
inStr = 0
|
|
nNest = 0
|
|
_ = argc
|
|
_ = argv
|
|
pStr = Xsqlite3_aggregate_context(tls, ctx, 0)
|
|
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
|
|
** always have been called to initialize it */
|
|
if !(pStr != 0) {
|
|
return
|
|
}
|
|
z = (*TJsonString)(unsafe.Pointer(pStr)).FzBuf
|
|
i = uint32(1)
|
|
for {
|
|
if v3 = uint64(i) < (*TJsonString)(unsafe.Pointer(pStr)).FnUsed; v3 {
|
|
v2 = **(**uint8)(__ccgo_up(z + uintptr(i)))
|
|
c = v2
|
|
}
|
|
if !(v3 && (libc.Int32FromUint8(v2) != int32(',') || inStr != 0 || nNest != 0)) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(c) == int32('"') {
|
|
inStr = libc.BoolInt32(!(inStr != 0))
|
|
} else {
|
|
if libc.Int32FromUint8(c) == int32('\\') {
|
|
i = i + 1
|
|
} else {
|
|
if !(inStr != 0) {
|
|
if libc.Int32FromUint8(c) == int32('{') || libc.Int32FromUint8(c) == int32('[') {
|
|
nNest = nNest + 1
|
|
}
|
|
if libc.Int32FromUint8(c) == int32('}') || libc.Int32FromUint8(c) == int32(']') {
|
|
nNest = nNest - 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if uint64(i) < (*TJsonString)(unsafe.Pointer(pStr)).FnUsed {
|
|
**(**Tu64)(__ccgo_up(pStr + 24)) -= uint64(i)
|
|
libc.Xmemmove(tls, z+1, z+uintptr(i+uint32(1)), (*TJsonString)(unsafe.Pointer(pStr)).FnUsed-uint64(1))
|
|
**(**uint8)(__ccgo_up(z + uintptr((*TJsonString)(unsafe.Pointer(pStr)).FnUsed))) = uint8(0)
|
|
} else {
|
|
(*TJsonString)(unsafe.Pointer(pStr)).FnUsed = uint64(1)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent
|
|
// ** arguments come in pairs where each pair contains a JSON path and
|
|
// ** content to insert or set at that patch. Do the updates
|
|
// ** and return the result.
|
|
// **
|
|
// ** The specific operation is determined by eEdit, which can be one
|
|
// ** of JEDIT_INS, JEDIT_REPL, JEDIT_SET, or JEDIT_AINS.
|
|
// */
|
|
func _jsonInsertIntoBlob(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr, eEdit int32) {
|
|
bp := tls.Alloc(80)
|
|
defer tls.Free(80)
|
|
var flgs, i, v1 int32
|
|
var p, zPath uintptr
|
|
var rc Tu32
|
|
var _ /* ax at bp+0 */ TJsonParse
|
|
_, _, _, _, _, _ = flgs, i, p, rc, zPath, v1
|
|
rc = uint32(0)
|
|
zPath = uintptr(0)
|
|
if argc == int32(1) {
|
|
v1 = 0
|
|
} else {
|
|
v1 = int32(JSON_EDITABLE)
|
|
}
|
|
flgs = v1
|
|
p = _jsonParseFuncArg(tls, ctx, **(**uintptr)(__ccgo_up(argv)), libc.Uint32FromInt32(flgs))
|
|
if p == uintptr(0) {
|
|
return
|
|
}
|
|
i = int32(1)
|
|
for {
|
|
if !(i < argc-int32(1)) {
|
|
break
|
|
}
|
|
if Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8))) == int32(SQLITE_NULL) {
|
|
goto _2
|
|
}
|
|
zPath = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8)))
|
|
if zPath == uintptr(0) {
|
|
Xsqlite3_result_error_nomem(tls, ctx)
|
|
_jsonParseFree(tls, p)
|
|
return
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zPath))) != int32('$') {
|
|
goto jsonInsertIntoBlob_patherror
|
|
}
|
|
if _jsonFunctionArgToBlob(tls, ctx, **(**uintptr)(__ccgo_up(argv + uintptr(i+int32(1))*8)), bp) != 0 {
|
|
_jsonParseReset(tls, bp)
|
|
_jsonParseFree(tls, p)
|
|
return
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zPath + 1))) == 0 {
|
|
if eEdit == int32(JEDIT_REPL) || eEdit == int32(JEDIT_SET) {
|
|
_jsonBlobEdit(tls, p, uint32(0), (*TJsonParse)(unsafe.Pointer(p)).FnBlob, (**(**TJsonParse)(__ccgo_up(bp))).FaBlob, (**(**TJsonParse)(__ccgo_up(bp))).FnBlob)
|
|
}
|
|
rc = uint32(0)
|
|
} else {
|
|
(*TJsonParse)(unsafe.Pointer(p)).FeEdit = libc.Uint8FromInt32(eEdit)
|
|
(*TJsonParse)(unsafe.Pointer(p)).FnIns = (**(**TJsonParse)(__ccgo_up(bp))).FnBlob
|
|
(*TJsonParse)(unsafe.Pointer(p)).FaIns = (**(**TJsonParse)(__ccgo_up(bp))).FaBlob
|
|
(*TJsonParse)(unsafe.Pointer(p)).Fdelta = 0
|
|
(*TJsonParse)(unsafe.Pointer(p)).FiDepth = uint16(0)
|
|
rc = _jsonLookupStep(tls, p, uint32(0), zPath+uintptr(1), uint32(0))
|
|
}
|
|
_jsonParseReset(tls, bp)
|
|
if rc == uint32(JSON_LOOKUP_NOTFOUND) {
|
|
goto _2
|
|
}
|
|
if rc >= uint32(JSON_LOOKUP_PATHERROR) {
|
|
goto jsonInsertIntoBlob_patherror
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + int32(2)
|
|
}
|
|
_jsonReturnParse(tls, ctx, p)
|
|
_jsonParseFree(tls, p)
|
|
return
|
|
goto jsonInsertIntoBlob_patherror
|
|
jsonInsertIntoBlob_patherror:
|
|
;
|
|
_jsonParseFree(tls, p)
|
|
_jsonBadPathError(tls, ctx, zPath, libc.Int32FromUint32(rc))
|
|
return
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** json_remove(JSON, PATH, ...)
|
|
// **
|
|
// ** Remove the named elements from JSON and return the result. malformed
|
|
// ** JSON or PATH arguments result in an error.
|
|
// */
|
|
func _jsonRemoveFunc(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
|
var i, v1 int32
|
|
var p, zPath uintptr
|
|
var rc Tu32
|
|
_, _, _, _, _ = i, p, rc, zPath, v1 /* The parse */
|
|
zPath = uintptr(0) /* Subroutine return code */
|
|
if argc < int32(1) {
|
|
return
|
|
}
|
|
if argc > int32(1) {
|
|
v1 = int32(JSON_EDITABLE)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
p = _jsonParseFuncArg(tls, ctx, **(**uintptr)(__ccgo_up(argv)), libc.Uint32FromInt32(v1))
|
|
if p == uintptr(0) {
|
|
return
|
|
}
|
|
i = int32(1)
|
|
for {
|
|
if !(i < argc) {
|
|
break
|
|
}
|
|
zPath = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8)))
|
|
if zPath == uintptr(0) {
|
|
goto json_remove_done
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zPath))) != int32('$') {
|
|
goto json_remove_patherror
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zPath + 1))) == 0 {
|
|
/* json_remove(j,'$') returns NULL */
|
|
goto json_remove_done
|
|
}
|
|
(*TJsonParse)(unsafe.Pointer(p)).FeEdit = uint8(JEDIT_DEL)
|
|
(*TJsonParse)(unsafe.Pointer(p)).Fdelta = 0
|
|
rc = _jsonLookupStep(tls, p, uint32(0), zPath+uintptr(1), uint32(0))
|
|
if rc >= uint32(JSON_LOOKUP_PATHERROR) {
|
|
if rc == uint32(JSON_LOOKUP_NOTFOUND) {
|
|
goto _2 /* No-op */
|
|
} else {
|
|
_jsonBadPathError(tls, ctx, zPath, libc.Int32FromUint32(rc))
|
|
}
|
|
goto json_remove_done
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_jsonReturnParse(tls, ctx, p)
|
|
_jsonParseFree(tls, p)
|
|
return
|
|
goto json_remove_patherror
|
|
json_remove_patherror:
|
|
;
|
|
_jsonBadPathError(tls, ctx, zPath, 0)
|
|
goto json_remove_done
|
|
json_remove_done:
|
|
;
|
|
_jsonParseFree(tls, p)
|
|
return
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** json_type(JSON)
|
|
// ** json_type(JSON, PATH)
|
|
// **
|
|
// ** Return the top-level "type" of a JSON string. json_type() raises an
|
|
// ** error if either the JSON or PATH inputs are not well-formed.
|
|
// */
|
|
func _jsonTypeFunc(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
|
var i Tu32
|
|
var p, zPath uintptr
|
|
_, _, _ = i, p, zPath /* The parse */
|
|
zPath = uintptr(0)
|
|
p = _jsonParseFuncArg(tls, ctx, **(**uintptr)(__ccgo_up(argv)), uint32(0))
|
|
if p == uintptr(0) {
|
|
return
|
|
}
|
|
if argc == int32(2) {
|
|
zPath = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
if zPath == uintptr(0) {
|
|
goto json_type_done
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zPath))) != int32('$') {
|
|
_jsonBadPathError(tls, ctx, zPath, 0)
|
|
goto json_type_done
|
|
}
|
|
i = _jsonLookupStep(tls, p, uint32(0), zPath+uintptr(1), uint32(0))
|
|
if i >= uint32(JSON_LOOKUP_PATHERROR) {
|
|
if i == uint32(JSON_LOOKUP_NOTFOUND) {
|
|
/* no-op */
|
|
} else {
|
|
_jsonBadPathError(tls, ctx, zPath, libc.Int32FromUint32(i))
|
|
}
|
|
goto json_type_done
|
|
}
|
|
} else {
|
|
i = uint32(0)
|
|
}
|
|
Xsqlite3_result_text(tls, ctx, _jsonbType[libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(p)).FaBlob + uintptr(i))))&int32(0x0f)], -int32(1), libc.UintptrFromInt32(0))
|
|
goto json_type_done
|
|
json_type_done:
|
|
;
|
|
_jsonParseFree(tls, p)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Open an mem file handle.
|
|
// */
|
|
func _memdbOpen(tls *libc.TLS, pVfs uintptr, zName uintptr, pFd uintptr, flags int32, pOutFlags uintptr) (r int32) {
|
|
var apNew, p, pFile, pVfsMutex, v3 uintptr
|
|
var i, szName, v2 int32
|
|
_, _, _, _, _, _, _, _ = apNew, i, p, pFile, pVfsMutex, szName, v2, v3
|
|
pFile = pFd
|
|
p = uintptr(0)
|
|
_ = pVfs
|
|
libc.Xmemset(tls, pFile, 0, uint64(24))
|
|
szName = _sqlite3Strlen30(tls, zName)
|
|
if szName > int32(1) && (libc.Int32FromUint8(**(**uint8)(__ccgo_up(zName))) == int32('/') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zName))) == int32('\\')) {
|
|
pVfsMutex = _sqlite3MutexAlloc(tls, int32(SQLITE_MUTEX_STATIC_VFS1))
|
|
Xsqlite3_mutex_enter(tls, pVfsMutex)
|
|
i = 0
|
|
for {
|
|
if !(i < _memdb_g.FnMemStore) {
|
|
break
|
|
}
|
|
if libc.Xstrcmp(tls, (*TMemStore)(unsafe.Pointer(**(**uintptr)(__ccgo_up(_memdb_g.FapMemStore + uintptr(i)*8)))).FzFName, zName) == 0 {
|
|
p = **(**uintptr)(__ccgo_up(_memdb_g.FapMemStore + uintptr(i)*8))
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if p == uintptr(0) {
|
|
p = _sqlite3Malloc(tls, uint64(72)+libc.Uint64FromInt64(int64(szName))+uint64(3))
|
|
if p == uintptr(0) {
|
|
Xsqlite3_mutex_leave(tls, pVfsMutex)
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
apNew = _sqlite3Realloc(tls, _memdb_g.FapMemStore, uint64(8)*libc.Uint64FromInt64(libc.Int64FromInt32(1)+int64(_memdb_g.FnMemStore)))
|
|
if apNew == uintptr(0) {
|
|
Xsqlite3_free(tls, p)
|
|
Xsqlite3_mutex_leave(tls, pVfsMutex)
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
v3 = uintptr(unsafe.Pointer(&_memdb_g))
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
**(**uintptr)(__ccgo_up(apNew + uintptr(v2)*8)) = p
|
|
_memdb_g.FapMemStore = apNew
|
|
libc.Xmemset(tls, p, 0, uint64(72))
|
|
(*TMemStore)(unsafe.Pointer(p)).FmFlags = libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_DESERIALIZE_RESIZEABLE) | libc.Int32FromInt32(SQLITE_DESERIALIZE_FREEONCLOSE))
|
|
(*TMemStore)(unsafe.Pointer(p)).FszMax = _sqlite3Config.FmxMemdbSize
|
|
(*TMemStore)(unsafe.Pointer(p)).FzFName = p + 1*72
|
|
libc.Xmemcpy(tls, (*TMemStore)(unsafe.Pointer(p)).FzFName, zName, libc.Uint64FromInt32(szName+int32(1)))
|
|
(*TMemStore)(unsafe.Pointer(p)).FpMutex = Xsqlite3_mutex_alloc(tls, SQLITE_MUTEX_FAST)
|
|
if (*TMemStore)(unsafe.Pointer(p)).FpMutex == uintptr(0) {
|
|
_memdb_g.FnMemStore = _memdb_g.FnMemStore - 1
|
|
Xsqlite3_free(tls, p)
|
|
Xsqlite3_mutex_leave(tls, pVfsMutex)
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TMemStore)(unsafe.Pointer(p)).FnRef = int32(1)
|
|
_memdbEnter(tls, p)
|
|
} else {
|
|
_memdbEnter(tls, p)
|
|
(*TMemStore)(unsafe.Pointer(p)).FnRef = (*TMemStore)(unsafe.Pointer(p)).FnRef + 1
|
|
}
|
|
Xsqlite3_mutex_leave(tls, pVfsMutex)
|
|
} else {
|
|
p = _sqlite3Malloc(tls, uint64(72))
|
|
if p == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
libc.Xmemset(tls, p, 0, uint64(72))
|
|
(*TMemStore)(unsafe.Pointer(p)).FmFlags = libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_DESERIALIZE_RESIZEABLE) | libc.Int32FromInt32(SQLITE_DESERIALIZE_FREEONCLOSE))
|
|
(*TMemStore)(unsafe.Pointer(p)).FszMax = _sqlite3Config.FmxMemdbSize
|
|
}
|
|
(*TMemFile)(unsafe.Pointer(pFile)).FpStore = p
|
|
if pOutFlags != uintptr(0) {
|
|
**(**int32)(__ccgo_up(pOutFlags)) = flags | int32(SQLITE_OPEN_MEMORY)
|
|
}
|
|
(*Tsqlite3_file)(unsafe.Pointer(pFd)).FpMethods = uintptr(unsafe.Pointer(&_memdb_io_methods))
|
|
_memdbLeave(tls, p)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Parameter zSuper is the name of a super-journal file. A single journal
|
|
// ** file that referred to the super-journal file has just been rolled back.
|
|
// ** This routine checks if it is possible to delete the super-journal file,
|
|
// ** and does so if it is.
|
|
// **
|
|
// ** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not
|
|
// ** available for use within this function.
|
|
// **
|
|
// ** When a super-journal file is created, it is populated with the names
|
|
// ** of all of its child journals, one after another, formatted as utf-8
|
|
// ** encoded text. The end of each child journal file is marked with a
|
|
// ** nul-terminator byte (0x00). i.e. the entire contents of a super-journal
|
|
// ** file for a transaction involving two databases might be:
|
|
// **
|
|
// ** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00"
|
|
// **
|
|
// ** A super-journal file may only be deleted once all of its child
|
|
// ** journals have been rolled back.
|
|
// **
|
|
// ** This function reads the contents of the super-journal file into
|
|
// ** memory and loops through each of the child journal names. For
|
|
// ** each child journal, it checks if:
|
|
// **
|
|
// ** * if the child journal exists, and if so
|
|
// ** * if the child journal contains a reference to super-journal
|
|
// ** file zSuper
|
|
// **
|
|
// ** If a child journal can be found that matches both of the criteria
|
|
// ** above, this function returns without doing anything. Otherwise, if
|
|
// ** no such child journal can be found, file zSuper is deleted from
|
|
// ** the file-system using sqlite3OsDelete().
|
|
// **
|
|
// ** If an IO error within this function, an error code is returned. This
|
|
// ** function allocates memory by calling sqlite3Malloc(). If an allocation
|
|
// ** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors
|
|
// ** occur, SQLITE_OK is returned.
|
|
// **
|
|
// ** TODO: This function allocates a single block of memory to load
|
|
// ** the entire contents of the super-journal file. This could be
|
|
// ** a couple of kilobytes or so - potentially larger than the page
|
|
// ** size.
|
|
// */
|
|
func _pager_delsuper(tls *libc.TLS, pPager uintptr, zSuper uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var bSeen, c, flags, flags1, rc int32
|
|
var pJournal, pSuper, pVfs, zFree, zJournal, zSuperJournal uintptr
|
|
var v1, v2, v3 uint8
|
|
var _ /* exists at bp+8 */ int32
|
|
var _ /* nSuperJournal at bp+0 */ Ti64
|
|
var _ /* zSuperPtr at bp+16 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _ = bSeen, c, flags, flags1, pJournal, pSuper, pVfs, rc, zFree, zJournal, zSuperJournal, v1, v2, v3
|
|
pVfs = (*TPager)(unsafe.Pointer(pPager)).FpVfs /* Malloc'd child-journal file descriptor */
|
|
zSuperJournal = uintptr(0) /* Pointer to one journal within MJ file */
|
|
zFree = uintptr(0) /* Free this buffer */
|
|
bSeen = 0 /* If super-journal contains pPager->zJournal */
|
|
/* Check if this looks like a real super-journal name. If it does not,
|
|
** return SQLITE_OK without attempting to delete it. This is to limit
|
|
** the degree to which a crafted journal file can be used to cause
|
|
** SQLite to delete arbitrary files. */
|
|
if _pagerIsSuperJrnlName(tls, zSuper) == 0 {
|
|
return SQLITE_OK
|
|
}
|
|
/* Allocate space for both the pJournal and pSuper file descriptors.
|
|
** If successful, open the super-journal file for reading.
|
|
*/
|
|
pSuper = _sqlite3MallocZero(tls, libc.Uint64FromInt64(int64(2)*int64((*Tsqlite3_vfs)(unsafe.Pointer(pVfs)).FszOsFile)))
|
|
if !(pSuper != 0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
pJournal = uintptr(0)
|
|
} else {
|
|
flags = libc.Int32FromInt32(SQLITE_OPEN_READONLY) | libc.Int32FromInt32(SQLITE_OPEN_SUPER_JOURNAL)
|
|
rc = _sqlite3OsOpen(tls, pVfs, zSuper, pSuper, flags, uintptr(0))
|
|
pJournal = pSuper + uintptr((*Tsqlite3_vfs)(unsafe.Pointer(pVfs)).FszOsFile)
|
|
}
|
|
if rc != SQLITE_OK {
|
|
goto delsuper_out
|
|
}
|
|
/* Load the entire super-journal file into space obtained from
|
|
** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain
|
|
** sufficient space (in zSuperPtr) to hold the names of super-journal
|
|
** files extracted from regular rollback-journals.
|
|
*/
|
|
rc = _sqlite3OsFileSize(tls, pSuper, bp)
|
|
if rc != SQLITE_OK {
|
|
goto delsuper_out
|
|
}
|
|
zFree = _sqlite3Malloc(tls, libc.Uint64FromInt64(int64(4)+**(**Ti64)(__ccgo_up(bp))+int64(2)))
|
|
if !(zFree != 0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
goto delsuper_out
|
|
} else {
|
|
}
|
|
v3 = libc.Uint8FromInt32(0)
|
|
**(**uint8)(__ccgo_up(zFree + 3)) = v3
|
|
v2 = v3
|
|
**(**uint8)(__ccgo_up(zFree + 2)) = v2
|
|
v1 = v2
|
|
**(**uint8)(__ccgo_up(zFree + 1)) = v1
|
|
**(**uint8)(__ccgo_up(zFree)) = v1
|
|
zSuperJournal = zFree + 4
|
|
rc = _sqlite3OsRead(tls, pSuper, zSuperJournal, int32(**(**Ti64)(__ccgo_up(bp))), 0)
|
|
if rc != SQLITE_OK {
|
|
goto delsuper_out
|
|
}
|
|
**(**uint8)(__ccgo_up(zSuperJournal + uintptr(**(**Ti64)(__ccgo_up(bp))))) = uint8(0)
|
|
**(**uint8)(__ccgo_up(zSuperJournal + uintptr(**(**Ti64)(__ccgo_up(bp))+int64(1)))) = uint8(0)
|
|
zJournal = zSuperJournal
|
|
for int64(zJournal)-int64(zSuperJournal) < **(**Ti64)(__ccgo_up(bp)) {
|
|
if libc.Xstrcmp(tls, zJournal, (*TPager)(unsafe.Pointer(pPager)).FzJournal) == 0 {
|
|
bSeen = int32(1)
|
|
} else {
|
|
rc = _sqlite3OsAccess(tls, pVfs, zJournal, SQLITE_ACCESS_EXISTS, bp+8)
|
|
if rc != SQLITE_OK {
|
|
goto delsuper_out
|
|
}
|
|
if **(**int32)(__ccgo_up(bp + 8)) != 0 {
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0)
|
|
flags1 = libc.Int32FromInt32(SQLITE_OPEN_READONLY) | libc.Int32FromInt32(SQLITE_OPEN_SUPER_JOURNAL)
|
|
rc = _sqlite3OsOpen(tls, pVfs, zJournal, pJournal, flags1, uintptr(0))
|
|
if rc != SQLITE_OK {
|
|
goto delsuper_out
|
|
}
|
|
rc = _readSuperJournal(tls, pJournal, uint64(1)+libc.Uint64FromInt32((*Tsqlite3_vfs)(unsafe.Pointer(pVfs)).FmxPathname), bp+16)
|
|
_sqlite3OsClose(tls, pJournal)
|
|
if rc != SQLITE_OK {
|
|
goto delsuper_out
|
|
}
|
|
c = libc.BoolInt32(**(**uintptr)(__ccgo_up(bp + 16)) != uintptr(0) && libc.Xstrcmp(tls, **(**uintptr)(__ccgo_up(bp + 16)), zSuper) == 0)
|
|
_freeSuperJournal(tls, **(**uintptr)(__ccgo_up(bp + 16)))
|
|
if c != 0 {
|
|
/* We have a match. Do not delete the super-journal file. */
|
|
goto delsuper_out
|
|
}
|
|
}
|
|
}
|
|
zJournal = zJournal + uintptr(_sqlite3Strlen30(tls, zJournal)+libc.Int32FromInt32(1))
|
|
}
|
|
_sqlite3OsClose(tls, pSuper)
|
|
if bSeen != 0 {
|
|
/* Only delete the super-journal if bSeen is true - indicating that
|
|
** the super-journal contained a pointer to this database's journal
|
|
** file. */
|
|
rc = _sqlite3OsDelete(tls, pVfs, zSuper, 0)
|
|
}
|
|
goto delsuper_out
|
|
delsuper_out:
|
|
;
|
|
Xsqlite3_free(tls, zFree)
|
|
if pSuper != 0 {
|
|
_sqlite3OsClose(tls, pSuper)
|
|
Xsqlite3_free(tls, pSuper)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compare two UTF-8 strings for equality where the first string is
|
|
// ** a GLOB or LIKE expression. Return values:
|
|
// **
|
|
// ** SQLITE_MATCH: Match
|
|
// ** SQLITE_NOMATCH: No match
|
|
// ** SQLITE_NOWILDCARDMATCH: No match in spite of having * or % wildcards.
|
|
// **
|
|
// ** Globbing rules:
|
|
// **
|
|
// ** '*' Matches any sequence of zero or more characters.
|
|
// **
|
|
// ** '?' Matches exactly one character.
|
|
// **
|
|
// ** [...] Matches one character from the enclosed list of
|
|
// ** characters.
|
|
// **
|
|
// ** [^...] Matches one character not in the enclosed list.
|
|
// **
|
|
// ** With the [...] and [^...] matching, a ']' character can be included
|
|
// ** in the list by making it the first character after '[' or '^'. A
|
|
// ** range of characters can be specified using '-'. Example:
|
|
// ** "[a-z]" matches any single lower-case letter. To match a '-', make
|
|
// ** it the last character in the list.
|
|
// **
|
|
// ** Like matching rules:
|
|
// **
|
|
// ** '%' Matches any sequence of zero or more characters
|
|
// **
|
|
// *** '_' Matches any one character
|
|
// **
|
|
// ** Ec Where E is the "esc" character and c is any other
|
|
// ** character, including '%', '_', and esc, match exactly c.
|
|
// **
|
|
// ** The comments within this routine usually assume glob matching.
|
|
// **
|
|
// ** This routine is usually quick, but can be N**2 in the worst case.
|
|
// */
|
|
func _patternCompare(tls *libc.TLS, _zPattern uintptr, _zString uintptr, pInfo uintptr, matchOther Tu32) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
*(*uintptr)(unsafe.Pointer(bp)) = _zPattern
|
|
*(*uintptr)(unsafe.Pointer(bp + 8)) = _zString
|
|
var bMatch, bMatch1, bMatch2, invert, seen, v13 int32
|
|
var c, c2, matchAll, matchOne, prior_c, v1, v4 Tu32
|
|
var noCase Tu8
|
|
var zEscaped, v3, v6 uintptr
|
|
var v2, v5 uint32
|
|
var _ /* zStop at bp+18 */ [3]uint8
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = bMatch, bMatch1, bMatch2, c, c2, invert, matchAll, matchOne, noCase, prior_c, seen, zEscaped, v1, v13, v2, v3, v4, v5, v6 /* Next pattern and input string chars */
|
|
matchOne = uint32((*TcompareInfo)(unsafe.Pointer(pInfo)).FmatchOne) /* "?" or "_" */
|
|
matchAll = uint32((*TcompareInfo)(unsafe.Pointer(pInfo)).FmatchAll) /* "*" or "%" */
|
|
noCase = (*TcompareInfo)(unsafe.Pointer(pInfo)).FnoCase /* True if uppercase==lowercase */
|
|
zEscaped = uintptr(0) /* One past the last escaped input char */
|
|
for {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) < int32(0x80) {
|
|
v3 = **(**uintptr)(__ccgo_up(bp))
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + 1
|
|
v2 = uint32(**(**Tu8)(__ccgo_up(v3)))
|
|
} else {
|
|
v2 = _sqlite3Utf8Read(tls, bp)
|
|
}
|
|
v1 = v2
|
|
c = v1
|
|
if !(v1 != uint32(0)) {
|
|
break
|
|
}
|
|
if c == matchAll { /* Match "*" */
|
|
/* Skip over multiple "*" characters in the pattern. If there
|
|
** are also "?" characters, skip those as well, but consume a
|
|
** single character of the input string for each "?" skipped */
|
|
for {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) < int32(0x80) {
|
|
v6 = **(**uintptr)(__ccgo_up(bp))
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + 1
|
|
v5 = uint32(**(**Tu8)(__ccgo_up(v6)))
|
|
} else {
|
|
v5 = _sqlite3Utf8Read(tls, bp)
|
|
}
|
|
v4 = v5
|
|
c = v4
|
|
if !(v4 == matchAll || c == matchOne && matchOne != uint32(0)) {
|
|
break
|
|
}
|
|
if c == matchOne && _sqlite3Utf8Read(tls, bp+8) == uint32(0) {
|
|
return int32(SQLITE_NOWILDCARDMATCH)
|
|
}
|
|
}
|
|
if c == uint32(0) {
|
|
return SQLITE_MATCH /* "*" at the end of the pattern matches */
|
|
} else {
|
|
if c == matchOther {
|
|
if libc.Int32FromUint8((*TcompareInfo)(unsafe.Pointer(pInfo)).FmatchSet) == 0 {
|
|
c = _sqlite3Utf8Read(tls, bp)
|
|
if c == uint32(0) {
|
|
return int32(SQLITE_NOWILDCARDMATCH)
|
|
}
|
|
} else {
|
|
/* "[...]" immediately follows the "*". We have to do a slow
|
|
** recursive search in this case, but it is an unusual case. */
|
|
/* '[' is a single-byte character */
|
|
for **(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8)))) != 0 {
|
|
bMatch = _patternCompare(tls, **(**uintptr)(__ccgo_up(bp))+uintptr(-libc.Int32FromInt32(1)), **(**uintptr)(__ccgo_up(bp + 8)), pInfo, matchOther)
|
|
if bMatch != int32(SQLITE_NOMATCH) {
|
|
return bMatch
|
|
}
|
|
v3 = **(**uintptr)(__ccgo_up(bp + 8))
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = **(**uintptr)(__ccgo_up(bp + 8)) + 1
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v3))) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8)))))&int32(0xc0) == int32(0x80) {
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = **(**uintptr)(__ccgo_up(bp + 8)) + 1
|
|
}
|
|
}
|
|
}
|
|
return int32(SQLITE_NOWILDCARDMATCH)
|
|
}
|
|
}
|
|
}
|
|
/* At this point variable c contains the first character of the
|
|
** pattern string past the "*". Search in the input string for the
|
|
** first matching character and recursively continue the match from
|
|
** that point.
|
|
**
|
|
** For a case-insensitive search, set variable cx to be the same as
|
|
** c but in the other case and search the input string for either
|
|
** c or cx.
|
|
*/
|
|
if c < uint32(0x80) {
|
|
if noCase != 0 {
|
|
(**(**[3]uint8)(__ccgo_up(bp + 18)))[0] = uint8(c & libc.Uint32FromInt32(^(libc.Int32FromUint8(_sqlite3CtypeMap[uint8(c)]) & libc.Int32FromInt32(0x20))))
|
|
(**(**[3]uint8)(__ccgo_up(bp + 18)))[int32(1)] = _sqlite3UpperToLower[uint8(c)]
|
|
(**(**[3]uint8)(__ccgo_up(bp + 18)))[int32(2)] = uint8(0)
|
|
} else {
|
|
(**(**[3]uint8)(__ccgo_up(bp + 18)))[0] = uint8(c)
|
|
(**(**[3]uint8)(__ccgo_up(bp + 18)))[int32(1)] = uint8(0)
|
|
}
|
|
for int32(1) != 0 {
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = **(**uintptr)(__ccgo_up(bp + 8)) + uintptr(libc.Xstrcspn(tls, **(**uintptr)(__ccgo_up(bp + 8)), bp+18))
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8))))) == 0 {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = **(**uintptr)(__ccgo_up(bp + 8)) + 1
|
|
bMatch1 = _patternCompare(tls, **(**uintptr)(__ccgo_up(bp)), **(**uintptr)(__ccgo_up(bp + 8)), pInfo, matchOther)
|
|
if bMatch1 != int32(SQLITE_NOMATCH) {
|
|
return bMatch1
|
|
}
|
|
}
|
|
} else {
|
|
for {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8))))) < int32(0x80) {
|
|
v3 = **(**uintptr)(__ccgo_up(bp + 8))
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = **(**uintptr)(__ccgo_up(bp + 8)) + 1
|
|
v2 = uint32(**(**Tu8)(__ccgo_up(v3)))
|
|
} else {
|
|
v2 = _sqlite3Utf8Read(tls, bp+8)
|
|
}
|
|
v1 = v2
|
|
c2 = v1
|
|
if !(v1 != uint32(0)) {
|
|
break
|
|
}
|
|
if c2 != c {
|
|
continue
|
|
}
|
|
bMatch2 = _patternCompare(tls, **(**uintptr)(__ccgo_up(bp)), **(**uintptr)(__ccgo_up(bp + 8)), pInfo, matchOther)
|
|
if bMatch2 != int32(SQLITE_NOMATCH) {
|
|
return bMatch2
|
|
}
|
|
}
|
|
}
|
|
return int32(SQLITE_NOWILDCARDMATCH)
|
|
}
|
|
if c == matchOther {
|
|
if libc.Int32FromUint8((*TcompareInfo)(unsafe.Pointer(pInfo)).FmatchSet) == 0 {
|
|
c = _sqlite3Utf8Read(tls, bp)
|
|
if c == uint32(0) {
|
|
return int32(SQLITE_NOMATCH)
|
|
}
|
|
zEscaped = **(**uintptr)(__ccgo_up(bp))
|
|
} else {
|
|
prior_c = uint32(0)
|
|
seen = 0
|
|
invert = 0
|
|
c = _sqlite3Utf8Read(tls, bp+8)
|
|
if c == uint32(0) {
|
|
return int32(SQLITE_NOMATCH)
|
|
}
|
|
c2 = _sqlite3Utf8Read(tls, bp)
|
|
if c2 == uint32('^') {
|
|
invert = int32(1)
|
|
c2 = _sqlite3Utf8Read(tls, bp)
|
|
}
|
|
if c2 == uint32(']') {
|
|
if c == uint32(']') {
|
|
seen = int32(1)
|
|
}
|
|
c2 = _sqlite3Utf8Read(tls, bp)
|
|
}
|
|
for c2 != 0 && c2 != uint32(']') {
|
|
if c2 == uint32('-') && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) != int32(']') && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) != 0 && prior_c > uint32(0) {
|
|
c2 = _sqlite3Utf8Read(tls, bp)
|
|
if c >= prior_c && c <= c2 {
|
|
seen = int32(1)
|
|
}
|
|
prior_c = uint32(0)
|
|
} else {
|
|
if c == c2 {
|
|
seen = int32(1)
|
|
}
|
|
prior_c = c2
|
|
}
|
|
c2 = _sqlite3Utf8Read(tls, bp)
|
|
}
|
|
if c2 == uint32(0) || seen^invert == 0 {
|
|
return int32(SQLITE_NOMATCH)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8))))) < int32(0x80) {
|
|
v3 = **(**uintptr)(__ccgo_up(bp + 8))
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = **(**uintptr)(__ccgo_up(bp + 8)) + 1
|
|
v2 = uint32(**(**Tu8)(__ccgo_up(v3)))
|
|
} else {
|
|
v2 = _sqlite3Utf8Read(tls, bp+8)
|
|
}
|
|
c2 = v2
|
|
if c == c2 {
|
|
continue
|
|
}
|
|
if noCase != 0 && libc.Int32FromUint8(_sqlite3UpperToLower[uint8(c)]) == libc.Int32FromUint8(_sqlite3UpperToLower[uint8(c2)]) && c < uint32(0x80) && c2 < uint32(0x80) {
|
|
continue
|
|
}
|
|
if c == matchOne && **(**uintptr)(__ccgo_up(bp)) != zEscaped && c2 != uint32(0) {
|
|
continue
|
|
}
|
|
return int32(SQLITE_NOMATCH)
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8))))) == 0 {
|
|
v13 = SQLITE_MATCH
|
|
} else {
|
|
v13 = int32(SQLITE_NOMATCH)
|
|
}
|
|
return v13
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is a Walker expression callback. pExpr is a node from the WHERE
|
|
// ** clause of a SELECT statement. This function examines pExpr to see if
|
|
// ** any substitutions based on the contents of pWalker->u.pConst should
|
|
// ** be made to pExpr or its immediate children.
|
|
// **
|
|
// ** A substitution is made if:
|
|
// **
|
|
// ** + pExpr is a column with an affinity other than BLOB that matches
|
|
// ** one of the columns in pWalker->u.pConst, or
|
|
// **
|
|
// ** + pExpr is a binary comparison operator (=, <=, >=, <, >) that
|
|
// ** uses an affinity other than TEXT and one of its immediate
|
|
// ** children is a column that matches one of the columns in
|
|
// ** pWalker->u.pConst.
|
|
// */
|
|
func _propagateConstantExprRewrite(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var pConst uintptr
|
|
_ = pConst
|
|
pConst = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
if (*TWhereConst)(unsafe.Pointer(pConst)).FbHasAffBlob != 0 {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) >= int32(TK_EQ) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) <= int32(TK_GE) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_IS) {
|
|
_propagateConstantExprRewriteOne(tls, pConst, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, 0)
|
|
if **(**Tu8)(__ccgo_up((*TWhereConst)(unsafe.Pointer(pConst)).FpOomFault)) != 0 {
|
|
return int32(WRC_Prune)
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3ExprAffinity(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft)) != int32(SQLITE_AFF_TEXT) {
|
|
_propagateConstantExprRewriteOne(tls, pConst, (*TExpr)(unsafe.Pointer(pExpr)).FpRight, 0)
|
|
}
|
|
}
|
|
}
|
|
return _propagateConstantExprRewriteOne(tls, pConst, pExpr, (*TWhereConst)(unsafe.Pointer(pConst)).FbHasAffBlob)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is a helper function for Walker callback propagateConstantExprRewrite().
|
|
// **
|
|
// ** Argument pExpr is a candidate expression to be replaced by a value. If
|
|
// ** pExpr is equivalent to one of the columns named in pWalker->u.pConst,
|
|
// ** then overwrite it with the corresponding value. Except, do not do so
|
|
// ** if argument bIgnoreAffBlob is non-zero and the affinity of pExpr
|
|
// ** is SQLITE_AFF_BLOB.
|
|
// */
|
|
func _propagateConstantExprRewriteOne(tls *libc.TLS, pConst uintptr, pExpr uintptr, bIgnoreAffBlob int32) (r int32) {
|
|
var i int32
|
|
var pColumn uintptr
|
|
_, _ = i, pColumn
|
|
if **(**Tu8)(__ccgo_up((*TWhereConst)(unsafe.Pointer(pConst)).FpOomFault)) != 0 {
|
|
return int32(WRC_Prune)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_COLUMN) {
|
|
return WRC_Continue
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&(libc.Uint32FromInt32(EP_FixedCol)|(*TWhereConst)(unsafe.Pointer(pConst)).FmExcludeOn) != uint32(0) {
|
|
return WRC_Continue
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TWhereConst)(unsafe.Pointer(pConst)).FnConst) {
|
|
break
|
|
}
|
|
pColumn = **(**uintptr)(__ccgo_up((*TWhereConst)(unsafe.Pointer(pConst)).FapExpr + uintptr(i*int32(2))*8))
|
|
if pColumn == pExpr {
|
|
goto _1
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pColumn)).FiTable != (*TExpr)(unsafe.Pointer(pExpr)).FiTable {
|
|
goto _1
|
|
}
|
|
if int32((*TExpr)(unsafe.Pointer(pColumn)).FiColumn) != int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) {
|
|
goto _1
|
|
}
|
|
if bIgnoreAffBlob != 0 && libc.Int32FromUint8(_sqlite3ExprAffinity(tls, pColumn)) <= int32(SQLITE_AFF_BLOB) {
|
|
break
|
|
}
|
|
/* A match is found. Add the EP_FixedCol property */
|
|
(*TWhereConst)(unsafe.Pointer(pConst)).FnChng = (*TWhereConst)(unsafe.Pointer(pConst)).FnChng + 1
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) &= ^libc.Uint32FromInt32(libc.Int32FromInt32(EP_Leaf))
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_FixedCol))
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FpLeft = _sqlite3ExprDup(tls, (*TParse)(unsafe.Pointer((*TWhereConst)(unsafe.Pointer(pConst)).FpParse)).Fdb, **(**uintptr)(__ccgo_up((*TWhereConst)(unsafe.Pointer(pConst)).FapExpr + uintptr(i*int32(2)+int32(1))*8)), 0)
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer((*TWhereConst)(unsafe.Pointer(pConst)).FpParse)).Fdb)).FmallocFailed != 0 {
|
|
return int32(WRC_Prune)
|
|
}
|
|
break
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return int32(WRC_Prune)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Apply a delta.
|
|
// **
|
|
// ** The output buffer should be big enough to hold the whole output
|
|
// ** file and a NUL terminator at the end. The delta_output_size()
|
|
// ** routine will determine this size for you.
|
|
// **
|
|
// ** The delta string should be null-terminated. But the delta string
|
|
// ** may contain embedded NUL characters (if the input and output are
|
|
// ** binary files) so we also have to pass in the length of the delta in
|
|
// ** the lenDelta parameter.
|
|
// **
|
|
// ** This function returns the size of the output file in bytes (excluding
|
|
// ** the final NUL terminator character). Except, if the delta string is
|
|
// ** malformed or intended for use with a source file other than zSrc,
|
|
// ** then this routine returns -1.
|
|
// **
|
|
// ** Refer to the delta_create() documentation above for a description
|
|
// ** of the delta file format.
|
|
// */
|
|
func _rbuDeltaApply(tls *libc.TLS, zSrc uintptr, lenSrc int32, _zDelta uintptr, _lenDelta int32, zOut uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
*(*uintptr)(unsafe.Pointer(bp)) = _zDelta
|
|
*(*int32)(unsafe.Pointer(bp + 8)) = _lenDelta
|
|
var cnt, limit, ofst, total uint32
|
|
_, _, _, _ = cnt, limit, ofst, total
|
|
total = uint32(0)
|
|
limit = _rbuDeltaGetInt(tls, bp, bp+8)
|
|
if **(**int32)(__ccgo_up(bp + 8)) <= 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) != int32('\n') {
|
|
/* ERROR: size integer not terminated by "\n" */
|
|
return -int32(1)
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + 1
|
|
**(**int32)(__ccgo_up(bp + 8)) = **(**int32)(__ccgo_up(bp + 8)) - 1
|
|
for **(**uint8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp)))) != 0 && **(**int32)(__ccgo_up(bp + 8)) > 0 {
|
|
cnt = _rbuDeltaGetInt(tls, bp, bp+8)
|
|
if **(**int32)(__ccgo_up(bp + 8)) <= 0 {
|
|
return -int32(1)
|
|
}
|
|
switch libc.Int32FromUint8(**(**uint8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) {
|
|
case int32('@'):
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + 1
|
|
**(**int32)(__ccgo_up(bp + 8)) = **(**int32)(__ccgo_up(bp + 8)) - 1
|
|
ofst = _rbuDeltaGetInt(tls, bp, bp+8)
|
|
if **(**int32)(__ccgo_up(bp + 8)) > 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) != int32(',') {
|
|
/* ERROR: copy command not terminated by ',' */
|
|
return -int32(1)
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + 1
|
|
**(**int32)(__ccgo_up(bp + 8)) = **(**int32)(__ccgo_up(bp + 8)) - 1
|
|
total = total + cnt
|
|
if total > limit {
|
|
/* ERROR: copy exceeds output file size */
|
|
return -int32(1)
|
|
}
|
|
if uint64(ofst)+uint64(cnt) > libc.Uint64FromInt32(lenSrc) {
|
|
/* ERROR: copy extends past end of input */
|
|
return -int32(1)
|
|
}
|
|
libc.Xmemcpy(tls, zOut, zSrc+uintptr(ofst), uint64(cnt))
|
|
zOut = zOut + uintptr(cnt)
|
|
case int32(':'):
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + 1
|
|
**(**int32)(__ccgo_up(bp + 8)) = **(**int32)(__ccgo_up(bp + 8)) - 1
|
|
total = total + cnt
|
|
if total > limit {
|
|
/* ERROR: insert command gives an output larger than predicted */
|
|
return -int32(1)
|
|
}
|
|
if libc.Int64FromUint32(cnt) > int64(**(**int32)(__ccgo_up(bp + 8))) {
|
|
/* ERROR: insert count exceeds size of delta */
|
|
return -int32(1)
|
|
}
|
|
libc.Xmemcpy(tls, zOut, **(**uintptr)(__ccgo_up(bp)), uint64(cnt))
|
|
zOut = zOut + uintptr(cnt)
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + uintptr(cnt)
|
|
**(**int32)(__ccgo_up(bp + 8)) = libc.Int32FromUint32(uint32(**(**int32)(__ccgo_up(bp + 8))) - cnt)
|
|
case int32(';'):
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp)) + 1
|
|
**(**int32)(__ccgo_up(bp + 8)) = **(**int32)(__ccgo_up(bp + 8)) - 1
|
|
**(**uint8)(__ccgo_up(zOut)) = uint8(0)
|
|
if total != limit {
|
|
/* ERROR: generated size does not match predicted size */
|
|
return -int32(1)
|
|
}
|
|
return libc.Int32FromUint32(total)
|
|
default:
|
|
/* ERROR: unknown delta operator */
|
|
return -int32(1)
|
|
}
|
|
}
|
|
/* ERROR: unterminated delta */
|
|
return -int32(1)
|
|
}
|
|
|
|
func _rbuDeltaOutputSize(tls *libc.TLS, _zDelta uintptr, _lenDelta int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
*(*uintptr)(unsafe.Pointer(bp)) = _zDelta
|
|
*(*int32)(unsafe.Pointer(bp + 8)) = _lenDelta
|
|
var size int32
|
|
_ = size
|
|
size = libc.Int32FromUint32(_rbuDeltaGetInt(tls, bp, bp+8))
|
|
if **(**int32)(__ccgo_up(bp + 8)) <= 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp))))) != int32('\n') {
|
|
/* ERROR: size integer not terminated by "\n" */
|
|
return -int32(1)
|
|
}
|
|
return size
|
|
}
|
|
|
|
/*
|
|
** End of code taken from fossil.
|
|
*************************************************************************/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function does the work for an sqlite3rbu_step() call.
|
|
// **
|
|
// ** The object-iterator (p->objiter) currently points to a valid object,
|
|
// ** and the input cursor (p->objiter.pSelect) currently points to a valid
|
|
// ** input row. Perform whatever processing is required and return.
|
|
// **
|
|
// ** If no error occurs, SQLITE_OK is returned. Otherwise, an error code
|
|
// ** and message is left in the RBU handle and a copy of the error code
|
|
// ** returned.
|
|
// */
|
|
func _rbuStep(tls *libc.TLS, p uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var c uint8
|
|
var eType, i int32
|
|
var pIter, pVal uintptr
|
|
var _ /* pUpdate at bp+8 */ uintptr
|
|
var _ /* zMask at bp+0 */ uintptr
|
|
_, _, _, _, _ = c, eType, i, pIter, pVal
|
|
pIter = p + 88
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
eType = _rbuStepType(tls, p, bp)
|
|
if eType != 0 {
|
|
if (*TRbuObjIter)(unsafe.Pointer(pIter)).FzIdx == uintptr(0) && (eType == int32(RBU_IDX_DELETE) || eType == int32(RBU_IDX_INSERT)) {
|
|
_rbuBadControlError(tls, p)
|
|
} else {
|
|
if eType == int32(RBU_REPLACE) {
|
|
if (*TRbuObjIter)(unsafe.Pointer(pIter)).FzIdx == uintptr(0) {
|
|
**(**Ti64)(__ccgo_up(p + 312)) += int64((*Tsqlite3rbu)(unsafe.Pointer(p)).Fobjiter.FnIndex)
|
|
_rbuStepOneOp(tls, p, int32(RBU_DELETE))
|
|
}
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
_rbuStepOneOp(tls, p, int32(RBU_INSERT))
|
|
}
|
|
} else {
|
|
if eType != int32(RBU_UPDATE) {
|
|
_rbuStepOneOp(tls, p, eType)
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
**(**Ti64)(__ccgo_up(p + 312)) -= int64((*Tsqlite3rbu)(unsafe.Pointer(p)).Fobjiter.FnIndex)
|
|
_rbuGetUpdateStmt(tls, p, pIter, **(**uintptr)(__ccgo_up(bp)), bp+8)
|
|
if **(**uintptr)(__ccgo_up(bp + 8)) != 0 {
|
|
i = 0
|
|
for {
|
|
if !((*Tsqlite3rbu)(unsafe.Pointer(p)).Frc == SQLITE_OK && i < (*TRbuObjIter)(unsafe.Pointer(pIter)).FnCol) {
|
|
break
|
|
}
|
|
c = **(**uint8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp)) + uintptr(**(**int32)(__ccgo_up((*TRbuObjIter)(unsafe.Pointer(pIter)).FaiSrcOrder + uintptr(i)*4)))))
|
|
pVal = Xsqlite3_column_value(tls, (*TRbuObjIter)(unsafe.Pointer(pIter)).FpSelect, i)
|
|
if **(**Tu8)(__ccgo_up((*TRbuObjIter)(unsafe.Pointer(pIter)).FabTblPk + uintptr(i))) != 0 || libc.Int32FromUint8(c) != int32('.') {
|
|
(*Tsqlite3rbu)(unsafe.Pointer(p)).Frc = Xsqlite3_bind_value(tls, **(**uintptr)(__ccgo_up(bp + 8)), i+int32(1), pVal)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(p)).Frc == SQLITE_OK && ((*TRbuObjIter)(unsafe.Pointer(pIter)).FeType == int32(RBU_PK_VTAB) || (*TRbuObjIter)(unsafe.Pointer(pIter)).FeType == int32(RBU_PK_NONE)) {
|
|
/* Bind the rbu_rowid value to column _rowid_ */
|
|
pVal = Xsqlite3_column_value(tls, (*TRbuObjIter)(unsafe.Pointer(pIter)).FpSelect, (*TRbuObjIter)(unsafe.Pointer(pIter)).FnCol+int32(1))
|
|
(*Tsqlite3rbu)(unsafe.Pointer(p)).Frc = Xsqlite3_bind_value(tls, **(**uintptr)(__ccgo_up(bp + 8)), (*TRbuObjIter)(unsafe.Pointer(pIter)).FnCol+int32(1), pVal)
|
|
}
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
Xsqlite3_step(tls, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
(*Tsqlite3rbu)(unsafe.Pointer(p)).Frc = _resetAndCollectError(tls, **(**uintptr)(__ccgo_up(bp + 8)), p+64)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (*Tsqlite3rbu)(unsafe.Pointer(p)).Frc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Parameter pJrnl is a file-handle open on a journal file. This function
|
|
// ** attempts to read a super-journal file name from the end of the journal
|
|
// ** file. If successful, it sets output parameter (*pzSuper) to point to a
|
|
// ** buffer containing the super-journal name as a nul-terminated string.
|
|
// ** The caller is responsible for freeing the buffer using freeSuperJournal().
|
|
// **
|
|
// ** Refer to comments above writeSuperJournal() for the format used to store
|
|
// ** a super-journal file name at the end of a journal file.
|
|
// **
|
|
// ** Parameter nSuper is passed the maximum allowable size of the super journal
|
|
// ** name in bytes. If the super-journal name in the journal is longer than
|
|
// ** nSuper bytes (including a nul-terminator), then this is handled as if no
|
|
// ** super-journal name were present in the journal.
|
|
// **
|
|
// ** If there is no super-journal name at the end of pJrnl, (*pzSuper) is
|
|
// ** set to 0 and SQLITE_OK is returned. Or, if an error occurs while reading
|
|
// ** the super-journal name, an SQLite error code is returned and (*pzSuper)
|
|
// ** is set to 0.
|
|
// */
|
|
func _readSuperJournal(tls *libc.TLS, pJrnl uintptr, nSuper Tu64, pzSuper uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var rc, v1, v2, v4, v6 int32
|
|
var u Tu32
|
|
var zOut uintptr
|
|
var v3, v5, v7 bool
|
|
var _ /* aMagic at bp+24 */ [8]uint8
|
|
var _ /* cksum at bp+16 */ Tu32
|
|
var _ /* len at bp+0 */ Tu32
|
|
var _ /* szJ at bp+8 */ Ti64
|
|
_, _, _, _, _, _, _, _, _, _ = rc, u, zOut, v1, v2, v3, v4, v5, v6, v7 /* A buffer to hold the magic header */
|
|
zOut = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(pzSuper)) = uintptr(0)
|
|
v1 = _sqlite3OsFileSize(tls, pJrnl, bp+8)
|
|
rc = v1
|
|
if v3 = SQLITE_OK != v1 || **(**Ti64)(__ccgo_up(bp + 8)) < int64(16); !v3 {
|
|
v2 = _read32bits(tls, pJrnl, **(**Ti64)(__ccgo_up(bp + 8))-int64(16), bp)
|
|
rc = v2
|
|
}
|
|
if v5 = v3 || SQLITE_OK != v2 || uint64(**(**Tu32)(__ccgo_up(bp))) >= nSuper || libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp))) > **(**Ti64)(__ccgo_up(bp + 8))-int64(16) || **(**Tu32)(__ccgo_up(bp)) == uint32(0); !v5 {
|
|
v4 = _read32bits(tls, pJrnl, **(**Ti64)(__ccgo_up(bp + 8))-int64(12), bp+16)
|
|
rc = v4
|
|
}
|
|
if v7 = v5 || SQLITE_OK != v4; !v7 {
|
|
v6 = _sqlite3OsRead(tls, pJrnl, bp+24, int32(8), **(**Ti64)(__ccgo_up(bp + 8))-int64(8))
|
|
rc = v6
|
|
}
|
|
if v7 || SQLITE_OK != v6 || libc.Xmemcmp(tls, bp+24, uintptr(unsafe.Pointer(&_aJournalMagic)), uint64(8)) != 0 {
|
|
return rc
|
|
}
|
|
zOut = _sqlite3MallocZero(tls, uint64(uint32(4)+**(**Tu32)(__ccgo_up(bp))+uint32(2)))
|
|
if !(zOut != 0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
} else {
|
|
zOut = zOut + 4
|
|
v1 = _sqlite3OsRead(tls, pJrnl, zOut, libc.Int32FromUint32(**(**Tu32)(__ccgo_up(bp))), **(**Ti64)(__ccgo_up(bp + 8))-int64(16)-libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp))))
|
|
rc = v1
|
|
if SQLITE_OK == v1 { /* Unsigned loop counter */
|
|
/* See if the checksum matches the super-journal name */
|
|
u = uint32(0)
|
|
for {
|
|
if !(u < **(**Tu32)(__ccgo_up(bp))) {
|
|
break
|
|
}
|
|
**(**Tu32)(__ccgo_up(bp + 16)) = **(**Tu32)(__ccgo_up(bp + 16)) - uint32(**(**uint8)(__ccgo_up(zOut + uintptr(u))))
|
|
goto _9
|
|
_9:
|
|
;
|
|
u = u + 1
|
|
}
|
|
}
|
|
if rc != SQLITE_OK || **(**Tu32)(__ccgo_up(bp + 16)) != 0 {
|
|
/* If the checksum doesn't add up, then one or more of the disk sectors
|
|
** containing the super-journal filename is corrupted. This means
|
|
** definitely roll back, so just return SQLITE_OK and report a (nul)
|
|
** super-journal filename. */
|
|
_freeSuperJournal(tls, zOut)
|
|
zOut = uintptr(0)
|
|
}
|
|
}
|
|
**(**uintptr)(__ccgo_up(pzSuper)) = zOut
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is the routine that actually formats the sqlite3_log() message.
|
|
// ** We house it in a separate routine from sqlite3_log() to avoid using
|
|
// ** stack space on small-stack systems when logging is disabled.
|
|
// **
|
|
// ** sqlite3_log() must render into a static buffer. It cannot dynamically
|
|
// ** allocate memory because it might be called while the memory allocator
|
|
// ** mutex is held.
|
|
// **
|
|
// ** sqlite3_str_vappendf() might ask for *temporary* memory allocations for
|
|
// ** certain format characters (%q) or for very large precisions or widths.
|
|
// ** Care must be taken that any sqlite3_log() calls that occur while the
|
|
// ** memory mutex is held do not use these mechanisms.
|
|
// */
|
|
func _renderLogMsg(tls *libc.TLS, iErrCode int32, zFormat uintptr, ap Tva_list) {
|
|
bp := tls.Alloc(736)
|
|
defer tls.Free(736)
|
|
var _ /* acc at bp+0 */ TStrAccum
|
|
var _ /* zMsg at bp+32 */ [700]uint8 /* Complete log message */
|
|
_sqlite3StrAccumInit(tls, bp, uintptr(0), bp+32, int32(700), 0)
|
|
Xsqlite3_str_vappendf(tls, bp, zFormat, ap)
|
|
(*(*func(*libc.TLS, uintptr, int32, uintptr))(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.FxLog})))(tls, _sqlite3Config.FpLogArg, iErrCode, _sqlite3StrAccumFinish(tls, bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pOrderBy is an ORDER BY or GROUP BY clause in SELECT statement pSelect.
|
|
// ** The Name context of the SELECT statement is pNC. zType is either
|
|
// ** "ORDER" or "GROUP" depending on which type of clause pOrderBy is.
|
|
// **
|
|
// ** This routine resolves each term of the clause into an expression.
|
|
// ** If the order-by term is an integer I between 1 and N (where N is the
|
|
// ** number of columns in the result set of the SELECT) then the expression
|
|
// ** in the resolution is a copy of the I-th result-set expression. If
|
|
// ** the order-by term is an identifier that corresponds to the AS-name of
|
|
// ** a result-set expression, then the term resolves to a copy of the
|
|
// ** result-set expression. Otherwise, the expression is resolved in
|
|
// ** the usual way - using sqlite3ResolveExprNames().
|
|
// **
|
|
// ** This routine returns the number of errors. If errors occur, then
|
|
// ** an appropriate error message might be left in pParse. (OOM errors
|
|
// ** excepted.)
|
|
// */
|
|
func _resolveOrderGroupBy(tls *libc.TLS, pNC uintptr, pSelect uintptr, pOrderBy uintptr, zType uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, j, nResult int32
|
|
var pE, pE2, pItem, pParse uintptr
|
|
var _ /* iCol at bp+0 */ int32
|
|
_, _, _, _, _, _, _ = i, j, nResult, pE, pE2, pItem, pParse /* Number of terms in the result set */
|
|
nResult = (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpEList)).FnExpr
|
|
pParse = (*TNameContext)(unsafe.Pointer(pNC)).FpParse
|
|
i = 0
|
|
pItem = pOrderBy + 8
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pOrderBy)).FnExpr) {
|
|
break
|
|
}
|
|
pE = (*TExprList_item)(unsafe.Pointer(pItem)).FpExpr
|
|
pE2 = _sqlite3ExprSkipCollateAndLikely(tls, pE)
|
|
if pE2 == uintptr(0) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zType))) != int32('G') {
|
|
**(**int32)(__ccgo_up(bp)) = _resolveAsName(tls, pParse, (*TSelect)(unsafe.Pointer(pSelect)).FpEList, pE2)
|
|
if **(**int32)(__ccgo_up(bp)) > 0 {
|
|
/* If an AS-name match is found, mark this ORDER BY column as being
|
|
** a copy of the iCol-th result-set column. The subsequent call to
|
|
** sqlite3ResolveOrderGroupBy() will convert the expression to a
|
|
** copy of the iCol-th result-set expression. */
|
|
(*(*struct {
|
|
FiOrderByCol Tu16
|
|
FiAlias Tu16
|
|
})(unsafe.Pointer(pItem + 24))).FiOrderByCol = libc.Uint16FromInt32(**(**int32)(__ccgo_up(bp)))
|
|
goto _1
|
|
}
|
|
}
|
|
if _sqlite3ExprIsInteger(tls, pE2, bp, uintptr(0)) != 0 {
|
|
/* The ORDER BY term is an integer constant. Again, set the column
|
|
** number so that sqlite3ResolveOrderGroupBy() will convert the
|
|
** order-by term to a copy of the result-set expression */
|
|
if **(**int32)(__ccgo_up(bp)) < int32(1) || **(**int32)(__ccgo_up(bp)) > int32(0xffff) {
|
|
_resolveOutOfRangeError(tls, pParse, zType, i+int32(1), nResult, pE2)
|
|
return int32(1)
|
|
}
|
|
(*(*struct {
|
|
FiOrderByCol Tu16
|
|
FiAlias Tu16
|
|
})(unsafe.Pointer(pItem + 24))).FiOrderByCol = libc.Uint16FromInt32(**(**int32)(__ccgo_up(bp)))
|
|
goto _1
|
|
}
|
|
/* Otherwise, treat the ORDER BY term as an ordinary expression */
|
|
(*(*struct {
|
|
FiOrderByCol Tu16
|
|
FiAlias Tu16
|
|
})(unsafe.Pointer(pItem + 24))).FiOrderByCol = uint16(0)
|
|
if _sqlite3ResolveExprNames(tls, pNC, pE) != 0 {
|
|
return int32(1)
|
|
}
|
|
j = 0
|
|
for {
|
|
if !(j < (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpEList)).FnExpr) {
|
|
break
|
|
}
|
|
if _sqlite3ExprCompare(tls, uintptr(0), pE, (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpEList + 8 + uintptr(j)*32))).FpExpr, -int32(1)) == 0 {
|
|
/* Since this expression is being changed into a reference
|
|
** to an identical expression in the result set, remove all Window
|
|
** objects belonging to the expression from the Select.pWin list. */
|
|
_windowRemoveExprFromSelect(tls, pSelect, pE)
|
|
(*(*struct {
|
|
FiOrderByCol Tu16
|
|
FiAlias Tu16
|
|
})(unsafe.Pointer(pItem + 24))).FiOrderByCol = libc.Uint16FromInt32(j + int32(1))
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
pItem += 32
|
|
}
|
|
return _sqlite3ResolveOrderGroupBy(tls, pParse, pSelect, pOrderBy, zType)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Rtree virtual table module xFilter method.
|
|
// */
|
|
func _rtreeFilter(tls *libc.TLS, pVtabCursor uintptr, idxNum int32, idxStr uintptr, argc int32, argv uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var eType, eType1, ii, rc int32
|
|
var iRowid Ti64
|
|
var iVal Tsqlite3_int64
|
|
var p, p1, pCsr, pNew, pRtree uintptr
|
|
var _ /* iCell at bp+8 */ int32
|
|
var _ /* iNode at bp+24 */ Ti64
|
|
var _ /* pLeaf at bp+16 */ uintptr
|
|
var _ /* pRoot at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = eType, eType1, iRowid, iVal, ii, p, p1, pCsr, pNew, pRtree, rc
|
|
pRtree = (*Tsqlite3_vtab_cursor)(unsafe.Pointer(pVtabCursor)).FpVtab
|
|
pCsr = pVtabCursor
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
rc = SQLITE_OK
|
|
**(**int32)(__ccgo_up(bp + 8)) = 0
|
|
_rtreeReference(tls, pRtree)
|
|
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
|
|
_resetCursor(tls, pCsr)
|
|
(*TRtreeCursor)(unsafe.Pointer(pCsr)).FiStrategy = idxNum
|
|
if idxNum == int32(1) { /* Search point for the leaf */
|
|
iRowid = Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
**(**Ti64)(__ccgo_up(bp + 24)) = 0
|
|
eType = Xsqlite3_value_numeric_type(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if eType == int32(SQLITE_INTEGER) || eType == int32(SQLITE_FLOAT) && 0 == _sqlite3IntFloatCompare(tls, iRowid, Xsqlite3_value_double(tls, **(**uintptr)(__ccgo_up(argv)))) {
|
|
rc = _findLeafNode(tls, pRtree, iRowid, bp+16, bp+24)
|
|
} else {
|
|
rc = SQLITE_OK
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0)
|
|
}
|
|
if rc == SQLITE_OK && **(**uintptr)(__ccgo_up(bp + 16)) != uintptr(0) {
|
|
p = _rtreeSearchPointNew(tls, pCsr, float64(0), uint8(0))
|
|
/* Always returns pCsr->sPoint */
|
|
**(**uintptr)(__ccgo_up(pCsr + 88)) = **(**uintptr)(__ccgo_up(bp + 16))
|
|
(*TRtreeSearchPoint)(unsafe.Pointer(p)).Fid = **(**Ti64)(__ccgo_up(bp + 24))
|
|
(*TRtreeSearchPoint)(unsafe.Pointer(p)).FeWithin = uint8(PARTLY_WITHIN)
|
|
rc = _nodeRowidIndex(tls, pRtree, **(**uintptr)(__ccgo_up(bp + 16)), iRowid, bp+8)
|
|
(*TRtreeSearchPoint)(unsafe.Pointer(p)).FiCell = libc.Uint8FromInt32(**(**int32)(__ccgo_up(bp + 8)))
|
|
} else {
|
|
(*TRtreeCursor)(unsafe.Pointer(pCsr)).FatEOF = uint8(1)
|
|
}
|
|
} else {
|
|
/* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
|
|
** with the configured constraints.
|
|
*/
|
|
rc = _nodeAcquire(tls, pRtree, int64(1), uintptr(0), bp)
|
|
if rc == SQLITE_OK && argc > 0 {
|
|
(*TRtreeCursor)(unsafe.Pointer(pCsr)).FaConstraint = Xsqlite3_malloc64(tls, uint64(uint64(24)*libc.Uint64FromInt32(argc)))
|
|
(*TRtreeCursor)(unsafe.Pointer(pCsr)).FnConstraint = argc
|
|
if !((*TRtreeCursor)(unsafe.Pointer(pCsr)).FaConstraint != 0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
} else {
|
|
libc.Xmemset(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FaConstraint, 0, uint64(24)*libc.Uint64FromInt32(argc))
|
|
libc.Xmemset(tls, pCsr+128, 0, uint64(4)*libc.Uint64FromInt32((*TRtree)(unsafe.Pointer(pRtree)).FiDepth+libc.Int32FromInt32(1)))
|
|
ii = 0
|
|
for {
|
|
if !(ii < argc) {
|
|
break
|
|
}
|
|
p1 = (*TRtreeCursor)(unsafe.Pointer(pCsr)).FaConstraint + uintptr(ii)*24
|
|
eType1 = Xsqlite3_value_numeric_type(tls, **(**uintptr)(__ccgo_up(argv + uintptr(ii)*8)))
|
|
(*TRtreeConstraint)(unsafe.Pointer(p1)).Fop = libc.Int32FromUint8(**(**uint8)(__ccgo_up(idxStr + uintptr(ii*int32(2)))))
|
|
(*TRtreeConstraint)(unsafe.Pointer(p1)).FiCoord = libc.Int32FromUint8(**(**uint8)(__ccgo_up(idxStr + uintptr(ii*int32(2)+int32(1))))) - int32('0')
|
|
if (*TRtreeConstraint)(unsafe.Pointer(p1)).Fop >= int32(RTREE_MATCH) {
|
|
/* A MATCH operator. The right-hand-side must be a blob that
|
|
** can be cast into an RtreeMatchArg object. One created using
|
|
** an sqlite3_rtree_geometry_callback() SQL user function.
|
|
*/
|
|
rc = _deserializeGeometry(tls, **(**uintptr)(__ccgo_up(argv + uintptr(ii)*8)), p1)
|
|
if rc != SQLITE_OK {
|
|
break
|
|
}
|
|
(*Tsqlite3_rtree_query_info)(unsafe.Pointer((*TRtreeConstraint)(unsafe.Pointer(p1)).FpInfo)).FnCoord = libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2)
|
|
(*Tsqlite3_rtree_query_info)(unsafe.Pointer((*TRtreeConstraint)(unsafe.Pointer(p1)).FpInfo)).FanQueue = pCsr + 128
|
|
(*Tsqlite3_rtree_query_info)(unsafe.Pointer((*TRtreeConstraint)(unsafe.Pointer(p1)).FpInfo)).FmxLevel = (*TRtree)(unsafe.Pointer(pRtree)).FiDepth + int32(1)
|
|
} else {
|
|
if eType1 == int32(SQLITE_INTEGER) {
|
|
iVal = Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv + uintptr(ii)*8)))
|
|
*(*TRtreeDValue)(unsafe.Pointer(p1 + 8)) = float64(iVal)
|
|
if iVal >= libc.Int64FromInt32(1)<<libc.Int32FromInt32(48) || iVal <= -(libc.Int64FromInt32(1)<<libc.Int32FromInt32(48)) {
|
|
if (*TRtreeConstraint)(unsafe.Pointer(p1)).Fop == int32(RTREE_LT) {
|
|
(*TRtreeConstraint)(unsafe.Pointer(p1)).Fop = int32(RTREE_LE)
|
|
}
|
|
if (*TRtreeConstraint)(unsafe.Pointer(p1)).Fop == int32(RTREE_GT) {
|
|
(*TRtreeConstraint)(unsafe.Pointer(p1)).Fop = int32(RTREE_GE)
|
|
}
|
|
}
|
|
} else {
|
|
if eType1 == int32(SQLITE_FLOAT) {
|
|
*(*TRtreeDValue)(unsafe.Pointer(p1 + 8)) = Xsqlite3_value_double(tls, **(**uintptr)(__ccgo_up(argv + uintptr(ii)*8)))
|
|
} else {
|
|
*(*TRtreeDValue)(unsafe.Pointer(p1 + 8)) = float64(0)
|
|
if eType1 == int32(SQLITE_NULL) {
|
|
(*TRtreeConstraint)(unsafe.Pointer(p1)).Fop = int32(RTREE_FALSE)
|
|
} else {
|
|
if (*TRtreeConstraint)(unsafe.Pointer(p1)).Fop == int32(RTREE_LT) || (*TRtreeConstraint)(unsafe.Pointer(p1)).Fop == int32(RTREE_LE) {
|
|
(*TRtreeConstraint)(unsafe.Pointer(p1)).Fop = int32(RTREE_TRUE)
|
|
} else {
|
|
(*TRtreeConstraint)(unsafe.Pointer(p1)).Fop = int32(RTREE_FALSE)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
/* Due to the resetCursor() call above */
|
|
pNew = _rtreeSearchPointNew(tls, pCsr, float64(0), libc.Uint8FromInt32((*TRtree)(unsafe.Pointer(pRtree)).FiDepth+libc.Int32FromInt32(1)))
|
|
if pNew == uintptr(0) { /* Because pCsr->bPoint was FALSE */
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TRtreeSearchPoint)(unsafe.Pointer(pNew)).Fid = int64(1)
|
|
(*TRtreeSearchPoint)(unsafe.Pointer(pNew)).FiCell = uint8(0)
|
|
(*TRtreeSearchPoint)(unsafe.Pointer(pNew)).FeWithin = uint8(PARTLY_WITHIN)
|
|
**(**uintptr)(__ccgo_up(pCsr + 88)) = **(**uintptr)(__ccgo_up(bp))
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
rc = _rtreeStepToLeaf(tls, pCsr)
|
|
}
|
|
}
|
|
_nodeRelease(tls, pRtree, **(**uintptr)(__ccgo_up(bp)))
|
|
_rtreeRelease(tls, pRtree)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo()
|
|
// ** interface.
|
|
// **
|
|
// ** For each FROM-clause subquery, add Column.zType, Column.zColl, and
|
|
// ** Column.affinity information to the Table structure that represents
|
|
// ** the result set of that subquery.
|
|
// **
|
|
// ** The Table structure that represents the result set was constructed
|
|
// ** by selectExpander() but the type and collation and affinity information
|
|
// ** was omitted at that point because identifiers had not yet been resolved.
|
|
// ** This routine is called after identifier resolution.
|
|
// */
|
|
func _selectAddSubqueryTypeInfo(tls *libc.TLS, pWalker uintptr, p uintptr) {
|
|
var i int32
|
|
var pFrom, pParse, pSel, pTab, pTabList uintptr
|
|
_, _, _, _, _, _ = i, pFrom, pParse, pSel, pTab, pTabList
|
|
if (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_HasTypeInfo) != 0 {
|
|
return
|
|
}
|
|
**(**Tu32)(__ccgo_up(p + 4)) |= uint32(SF_HasTypeInfo)
|
|
pParse = (*TWalker)(unsafe.Pointer(pWalker)).FpParse
|
|
pTabList = (*TSelect)(unsafe.Pointer(p)).FpSrc
|
|
i = 0
|
|
pFrom = pTabList + 8
|
|
for {
|
|
if !(i < (*TSrcList)(unsafe.Pointer(pTabList)).FnSrc) {
|
|
break
|
|
}
|
|
pTab = (*TSrcItem)(unsafe.Pointer(pFrom)).FpSTab
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_Ephemeral) != uint32(0) && int32(*(*uint32)(unsafe.Pointer(pFrom + 24 + 4))&0x4>>2) != 0 {
|
|
/* A sub-query in the FROM clause of a SELECT */
|
|
pSel = (*TSubquery)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pFrom + 72)))).FpSelect
|
|
_sqlite3SubqueryColumnTypes(tls, pParse, pTab, pSel, uint8(SQLITE_AFF_NONE))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
pFrom += 80
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
// ** called. Otherwise, append the string zStr enclosed in quotes (") and
|
|
// ** with any embedded quote characters escaped to the buffer. No
|
|
// ** nul-terminator byte is written.
|
|
// **
|
|
// ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
|
|
// ** returning.
|
|
// */
|
|
func _sessionAppendIdent(tls *libc.TLS, p uintptr, zStr uintptr, pRc uintptr) {
|
|
var nStr int32
|
|
var zIn, zOut, v1, v2 uintptr
|
|
_, _, _, _, _ = nStr, zIn, zOut, v1, v2
|
|
nStr = _sqlite3Strlen30(tls, zStr)*int32(2) + int32(2) + int32(2)
|
|
if 0 == _sessionBufferGrow(tls, p, int64(nStr), pRc) {
|
|
zOut = (*TSessionBuffer)(unsafe.Pointer(p)).FaBuf + uintptr((*TSessionBuffer)(unsafe.Pointer(p)).FnBuf)
|
|
zIn = zStr
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8('"')
|
|
if zIn != uintptr(0) {
|
|
for **(**uint8)(__ccgo_up(zIn)) != 0 {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zIn))) == int32('"') {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8('"')
|
|
}
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
v2 = zIn
|
|
zIn = zIn + 1
|
|
**(**uint8)(__ccgo_up(v1)) = **(**uint8)(__ccgo_up(v2))
|
|
}
|
|
}
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8('"')
|
|
(*TSessionBuffer)(unsafe.Pointer(p)).FnBuf = int32(int64(zOut) - int64((*TSessionBuffer)(unsafe.Pointer(p)).FaBuf))
|
|
**(**Tu8)(__ccgo_up((*TSessionBuffer)(unsafe.Pointer(p)).FaBuf + uintptr((*TSessionBuffer)(unsafe.Pointer(p)).FnBuf))) = uint8(0x00)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add a new CHECK constraint to the table currently under construction.
|
|
// */
|
|
func _sqlite3AddCheckConstraint(tls *libc.TLS, pParse uintptr, pCheckExpr uintptr, zStart uintptr, zEnd uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pTab uintptr
|
|
var _ /* t at bp+0 */ TToken
|
|
_, _ = db, pTab
|
|
pTab = (*TParse)(unsafe.Pointer(pParse)).FpNewTable
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if pTab != 0 && !(libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) == libc.Int32FromInt32(PARSE_MODE_DECLARE_VTAB)) && !(_sqlite3BtreeIsReadonly(tls, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr((*Tsqlite3)(unsafe.Pointer(db)).Finit1.FiDb)*32))).FpBt) != 0) {
|
|
(*TTable)(unsafe.Pointer(pTab)).FpCheck = _sqlite3ExprListAppend(tls, pParse, (*TTable)(unsafe.Pointer(pTab)).FpCheck, pCheckExpr)
|
|
if (*(*struct {
|
|
FaddrCrTab int32
|
|
FregRowid int32
|
|
FregRoot int32
|
|
FconstraintName TToken
|
|
})(unsafe.Pointer(pParse + 256))).FconstraintName.Fn != 0 {
|
|
_sqlite3ExprListSetName(tls, pParse, (*TTable)(unsafe.Pointer(pTab)).FpCheck, pParse+256+16, int32(1))
|
|
} else {
|
|
zStart = zStart + 1
|
|
for {
|
|
if !(libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(zStart)))])&int32(0x01) != 0) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
zStart = zStart + 1
|
|
}
|
|
for libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(zEnd + uintptr(-libc.Int32FromInt32(1)))))])&int32(0x01) != 0 {
|
|
zEnd = zEnd - 1
|
|
}
|
|
(**(**TToken)(__ccgo_up(bp))).Fz = zStart
|
|
(**(**TToken)(__ccgo_up(bp))).Fn = libc.Uint32FromInt32(int32(int64(zEnd) - int64((**(**TToken)(__ccgo_up(bp))).Fz)))
|
|
_sqlite3ExprListSetName(tls, pParse, (*TTable)(unsafe.Pointer(pTab)).FpCheck, bp, int32(1))
|
|
}
|
|
} else {
|
|
_sqlite3ExprDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pCheckExpr)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The most recently coded instruction was an OP_Column to retrieve the
|
|
// ** i-th column of table pTab. This routine sets the P4 parameter of the
|
|
// ** OP_Column to the default value, if any.
|
|
// **
|
|
// ** The default value of a column is specified by a DEFAULT clause in the
|
|
// ** column definition. This was either supplied by the user when the table
|
|
// ** was created, or added later to the table definition by an ALTER TABLE
|
|
// ** command. If the latter, then the row-records in the table btree on disk
|
|
// ** may not contain a value for the column and the default value, taken
|
|
// ** from the P4 parameter of the OP_Column instruction, is returned instead.
|
|
// ** If the former, then all row-records are guaranteed to include a value
|
|
// ** for the column and the P4 value is not required.
|
|
// **
|
|
// ** Column definitions created by an ALTER TABLE command may only have
|
|
// ** literal default values specified: a number, null or a string. (If a more
|
|
// ** complicated default expression value was provided, it is evaluated
|
|
// ** when the ALTER TABLE is executed and one of the literal values written
|
|
// ** into the sqlite_schema table.)
|
|
// **
|
|
// ** Therefore, the P4 parameter is only required if the default value for
|
|
// ** the column is a literal number, string or null. The sqlite3ValueFromExpr()
|
|
// ** function is capable of transforming these types of expressions into
|
|
// ** sqlite3_value objects.
|
|
// **
|
|
// ** If column as REAL affinity and the table is an ordinary b-tree table
|
|
// ** (not a virtual table) then the value might have been stored as an
|
|
// ** integer. In that case, add an OP_RealAffinity opcode to make sure
|
|
// ** it has been converted into REAL.
|
|
// */
|
|
func _sqlite3ColumnDefault(tls *libc.TLS, v uintptr, pTab uintptr, i int32, iReg int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var enc Tu8
|
|
var pCol uintptr
|
|
var _ /* pValue at bp+0 */ uintptr
|
|
_, _ = enc, pCol
|
|
pCol = (*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16
|
|
if (*TColumn)(unsafe.Pointer(pCol)).FiDflt != 0 {
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
enc = (*Tsqlite3)(unsafe.Pointer(_sqlite3VdbeDb(tls, v))).Fenc
|
|
_sqlite3ValueFromExpr(tls, _sqlite3VdbeDb(tls, v), _sqlite3ColumnExpr(tls, pTab, pCol), enc, (*TColumn)(unsafe.Pointer(pCol)).Faffinity, bp)
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
_sqlite3VdbeAppendP4(tls, v, **(**uintptr)(__ccgo_up(bp)), -int32(11))
|
|
}
|
|
}
|
|
if libc.Int32FromUint8((*TColumn)(unsafe.Pointer(pCol)).Faffinity) == int32(SQLITE_AFF_REAL) && !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_VTAB)) {
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_RealAffinity), iReg)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The text between zStart and zEnd represents a phrase within a larger
|
|
// ** SQL statement. Make a copy of this phrase in space obtained form
|
|
// ** sqlite3DbMalloc(). Omit leading and trailing whitespace.
|
|
// */
|
|
func _sqlite3DbSpanDup(tls *libc.TLS, db uintptr, zStart uintptr, zEnd uintptr) (r uintptr) {
|
|
var n int32
|
|
_ = n
|
|
for libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(zStart)))])&int32(0x01) != 0 {
|
|
zStart = zStart + 1
|
|
}
|
|
n = int32(int64(zEnd) - int64(zStart))
|
|
for libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(zStart + uintptr(n-int32(1)))))])&int32(0x01) != 0 {
|
|
n = n - 1
|
|
}
|
|
return _sqlite3DbStrNDup(tls, db, zStart, libc.Uint64FromInt32(n))
|
|
}
|
|
|
|
func _sqlite3DbStrNDup(tls *libc.TLS, db uintptr, z uintptr, n Tu64) (r uintptr) {
|
|
var zNew, v1 uintptr
|
|
_, _ = zNew, v1
|
|
if z != 0 {
|
|
v1 = _sqlite3DbMallocRawNN(tls, db, n+uint64(1))
|
|
} else {
|
|
v1 = uintptr(0)
|
|
}
|
|
zNew = v1
|
|
if zNew != 0 {
|
|
libc.Xmemcpy(tls, zNew, z, n)
|
|
**(**uint8)(__ccgo_up(zNew + uintptr(n))) = uint8(0)
|
|
}
|
|
return zNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the input token p is quoted, try to adjust the token to remove
|
|
// ** the quotes. This is not always possible:
|
|
// **
|
|
// ** "abc" -> abc
|
|
// ** "ab""cd" -> (not possible because of the interior "")
|
|
// **
|
|
// ** Remove the quotes if possible. This is a optimization. The overall
|
|
// ** system should still return the correct answer even if this routine
|
|
// ** is always a no-op.
|
|
// */
|
|
func _sqlite3DequoteToken(tls *libc.TLS, p uintptr) {
|
|
var i uint32
|
|
_ = i
|
|
if (*TToken)(unsafe.Pointer(p)).Fn < uint32(2) {
|
|
return
|
|
}
|
|
if !(libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up((*TToken)(unsafe.Pointer(p)).Fz)))])&libc.Int32FromInt32(0x80) != 0) {
|
|
return
|
|
}
|
|
i = uint32(1)
|
|
for {
|
|
if !(i < (*TToken)(unsafe.Pointer(p)).Fn-uint32(1)) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up((*TToken)(unsafe.Pointer(p)).Fz + uintptr(i))))])&int32(0x80) != 0 {
|
|
return
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**uint32)(__ccgo_up(p + 8)) -= uint32(2)
|
|
(*TToken)(unsafe.Pointer(p)).Fz = (*TToken)(unsafe.Pointer(p)).Fz + 1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the 'affinity' of the expression pExpr if any.
|
|
// **
|
|
// ** If pExpr is a column, a reference to a column via an 'AS' alias,
|
|
// ** or a sub-select with a column as the return value, then the
|
|
// ** affinity of that column is returned. Otherwise, 0x00 is returned,
|
|
// ** indicating no affinity for the expression.
|
|
// **
|
|
// ** i.e. the WHERE clause expressions in the following statements all
|
|
// ** have an affinity:
|
|
// **
|
|
// ** CREATE TABLE t1(a);
|
|
// ** SELECT * FROM t1 WHERE a;
|
|
// ** SELECT a AS b FROM t1 WHERE b;
|
|
// ** SELECT * FROM t1 WHERE (select a from t1);
|
|
// */
|
|
func _sqlite3ExprAffinity(tls *libc.TLS, pExpr uintptr) (r uint8) {
|
|
var op int32
|
|
_ = op
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop)
|
|
for int32(1) != 0 {
|
|
if op == int32(TK_COLUMN) || op == int32(TK_AGG_COLUMN) && *(*uintptr)(unsafe.Pointer(pExpr + 64)) != uintptr(0) {
|
|
return _sqlite3TableColumnAffinity(tls, *(*uintptr)(unsafe.Pointer(pExpr + 64)), int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn))
|
|
}
|
|
if op == int32(TK_SELECT) {
|
|
return _sqlite3ExprAffinity(tls, (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FpEList + 8))).FpExpr)
|
|
}
|
|
if op == int32(TK_CAST) {
|
|
return _sqlite3AffinityType(tls, *(*uintptr)(unsafe.Pointer(pExpr + 8)), uintptr(0))
|
|
}
|
|
if op == int32(TK_SELECT_COLUMN) {
|
|
return _sqlite3ExprAffinity(tls, (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pExpr)).FpLeft + 32)))).FpEList + 8 + uintptr((*TExpr)(unsafe.Pointer(pExpr)).FiColumn)*32))).FpExpr)
|
|
}
|
|
if op == int32(TK_VECTOR) || op == int32(TK_FUNCTION) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).FaffExpr) == int32(SQLITE_AFF_DEFER) {
|
|
return _sqlite3ExprAffinity(tls, (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)) + 8))).FpExpr)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Skip)|libc.Int32FromInt32(EP_IfNullRow)) != uint32(0) {
|
|
pExpr = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop)
|
|
continue
|
|
}
|
|
if op != int32(TK_REGISTER) {
|
|
break
|
|
}
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop2)
|
|
if op == int32(TK_REGISTER) {
|
|
break
|
|
}
|
|
}
|
|
return (*TExpr)(unsafe.Pointer(pExpr)).FaffExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is the core allocator for Expr nodes.
|
|
// **
|
|
// ** Construct a new expression node and return a pointer to it. Memory
|
|
// ** for this node and for the pToken argument is a single allocation
|
|
// ** obtained from sqlite3DbMalloc(). The calling function
|
|
// ** is responsible for making sure the node eventually gets freed.
|
|
// **
|
|
// ** If dequote is true, then the token (if it exists) is dequoted.
|
|
// ** If dequote is false, no dequoting is performed. The deQuote
|
|
// ** parameter is ignored if pToken is NULL or if the token does not
|
|
// ** appear to be quoted. If the quotes were of the form "..." (double-quotes)
|
|
// ** then the EP_DblQuoted flag is set on the expression node.
|
|
// **
|
|
// ** Special case (tag-20240227-a): If op==TK_INTEGER and pToken points to
|
|
// ** a string that can be translated into a 32-bit integer, then the token is
|
|
// ** not stored in u.zToken. Instead, the integer values is written
|
|
// ** into u.iValue and the EP_IntValue flag is set. No extra storage
|
|
// ** is allocated to hold the integer text and the dequote flag is ignored.
|
|
// ** See also tag-20240227-b.
|
|
// */
|
|
func _sqlite3ExprAlloc(tls *libc.TLS, db uintptr, op int32, pToken uintptr, dequote int32) (r uintptr) {
|
|
var nExtra int32
|
|
var pNew uintptr
|
|
var v1 uint32
|
|
_, _, _ = nExtra, pNew, v1
|
|
if pToken != 0 {
|
|
v1 = (*TToken)(unsafe.Pointer(pToken)).Fn + uint32(1)
|
|
} else {
|
|
v1 = uint32(0)
|
|
}
|
|
nExtra = libc.Int32FromUint32(v1)
|
|
pNew = _sqlite3DbMallocRawNN(tls, db, uint64(uint64(72)+libc.Uint64FromInt32(nExtra)))
|
|
if pNew != 0 {
|
|
libc.Xmemset(tls, pNew, 0, uint64(72))
|
|
(*TExpr)(unsafe.Pointer(pNew)).Fop = libc.Uint8FromInt32(op)
|
|
(*TExpr)(unsafe.Pointer(pNew)).FiAgg = int16(-int32(1))
|
|
if nExtra != 0 {
|
|
*(*uintptr)(unsafe.Pointer(pNew + 8)) = pNew + 1*72
|
|
if (*TToken)(unsafe.Pointer(pToken)).Fn != 0 {
|
|
libc.Xmemcpy(tls, *(*uintptr)(unsafe.Pointer(pNew + 8)), (*TToken)(unsafe.Pointer(pToken)).Fz, uint64((*TToken)(unsafe.Pointer(pToken)).Fn))
|
|
}
|
|
**(**uint8)(__ccgo_up(*(*uintptr)(unsafe.Pointer(pNew + 8)) + uintptr((*TToken)(unsafe.Pointer(pToken)).Fn))) = uint8(0)
|
|
if dequote != 0 && libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(*(*uintptr)(unsafe.Pointer(pNew + 8)))))])&int32(0x80) != 0 {
|
|
_sqlite3DequoteExpr(tls, pNew)
|
|
}
|
|
}
|
|
(*TExpr)(unsafe.Pointer(pNew)).FnHeight = int32(1)
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will compute the value of generated column pCol
|
|
// ** and store the result in register regOut
|
|
// */
|
|
func _sqlite3ExprCodeGeneratedColumn(tls *libc.TLS, pParse uintptr, pTab uintptr, pCol uintptr, regOut int32) {
|
|
var iAddr, nErr, p3 int32
|
|
var v uintptr
|
|
_, _, _, _ = iAddr, nErr, p3, v
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
nErr = (*TParse)(unsafe.Pointer(pParse)).FnErr
|
|
if (*TParse)(unsafe.Pointer(pParse)).FiSelfTab > 0 {
|
|
iAddr = _sqlite3VdbeAddOp3(tls, v, int32(OP_IfNullRow), (*TParse)(unsafe.Pointer(pParse)).FiSelfTab-int32(1), 0, regOut)
|
|
} else {
|
|
iAddr = 0
|
|
}
|
|
_sqlite3ExprCodeCopy(tls, pParse, _sqlite3ColumnExpr(tls, pTab, pCol), regOut)
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FcolFlags)&int32(COLFLAG_VIRTUAL) != 0 && (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_Strict) != uint32(0) {
|
|
p3 = int32(2) + int32((int64(pCol)-int64((*TTable)(unsafe.Pointer(pTab)).FaCol))/16)
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_TypeCheck), regOut, int32(1), p3, pTab, -int32(5))
|
|
} else {
|
|
if libc.Int32FromUint8((*TColumn)(unsafe.Pointer(pCol)).Faffinity) >= int32(SQLITE_AFF_TEXT) {
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_Affinity), regOut, int32(1), 0, pCol+9, int32(1))
|
|
}
|
|
}
|
|
if iAddr != 0 {
|
|
_sqlite3VdbeJumpHere(tls, v, iAddr)
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr > nErr {
|
|
(*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FerrByteOffset = -int32(1)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for an IN expression.
|
|
// **
|
|
// ** x IN (SELECT ...)
|
|
// ** x IN (value, value, ...)
|
|
// **
|
|
// ** The left-hand side (LHS) is a scalar or vector expression. The
|
|
// ** right-hand side (RHS) is an array of zero or more scalar values, or a
|
|
// ** subquery. If the RHS is a subquery, the number of result columns must
|
|
// ** match the number of columns in the vector on the LHS. If the RHS is
|
|
// ** a list of values, the LHS must be a scalar.
|
|
// **
|
|
// ** The IN operator is true if the LHS value is contained within the RHS.
|
|
// ** The result is false if the LHS is definitely not in the RHS. The
|
|
// ** result is NULL if the presence of the LHS in the RHS cannot be
|
|
// ** determined due to NULLs.
|
|
// **
|
|
// ** This routine generates code that jumps to destIfFalse if the LHS is not
|
|
// ** contained within the RHS. If due to NULLs we cannot determine if the LHS
|
|
// ** is contained in the RHS then jump to destIfNull. If the LHS is contained
|
|
// ** within the RHS then fall through.
|
|
// **
|
|
// ** See the separate in-operator.md documentation file in the canonical
|
|
// ** SQLite source tree for additional information.
|
|
// */
|
|
func _sqlite3ExprCodeIN(tls *libc.TLS, pParse uintptr, pExpr uintptr, destIfFalse int32, destIfNull int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var addrTop, addrTruthOp, destNotNull, destStep2, destStep6, eType, i, ii, labelOk, nVector, op, op1, r2, r3, rLhs, rLhsOrig, regCkNull, v3 int32
|
|
var aiMap, p, p1, pColl, pColl1, pLeft, pList, pOp, pRhs, v, zAff, v1 uintptr
|
|
var okConstFactor Tu8
|
|
var _ /* iDummy at bp+4 */ int32
|
|
var _ /* iTab at bp+8 */ int32
|
|
var _ /* rRhsHasNull at bp+0 */ int32
|
|
var _ /* regToFree at bp+12 */ int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addrTop, addrTruthOp, aiMap, destNotNull, destStep2, destStep6, eType, i, ii, labelOk, nVector, okConstFactor, op, op1, p, p1, pColl, pColl1, pLeft, pList, pOp, pRhs, r2, r3, rLhs, rLhsOrig, regCkNull, v, zAff, v1, v3
|
|
**(**int32)(__ccgo_up(bp)) = 0 /* Statement under construction */
|
|
aiMap = uintptr(0) /* Map from vector field to index column */
|
|
zAff = uintptr(0) /* Where to jump when NULLs seen in step 2 */
|
|
destStep6 = 0 /* Top of the step-6 loop */
|
|
**(**int32)(__ccgo_up(bp + 8)) = 0 /* Index to use */
|
|
okConstFactor = libc.Uint8FromInt32(int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40)) & 0x80 >> 7)))
|
|
pLeft = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
if _sqlite3ExprCheckIN(tls, pParse, pExpr) != 0 {
|
|
return
|
|
}
|
|
zAff = _exprINAffinity(tls, pParse, pExpr)
|
|
nVector = _sqlite3ExprVectorSize(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft)
|
|
aiMap = _sqlite3DbMallocZero(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(libc.Uint64FromInt32(nVector)*uint64(4)))
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FmallocFailed != 0 {
|
|
goto sqlite3ExprCodeIN_oom_error
|
|
}
|
|
/* Attempt to compute the RHS. After this step, if anything other than
|
|
** IN_INDEX_NOOP is returned, the table opened with cursor iTab
|
|
** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
|
|
** the RHS has not yet been coded. */
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
/* OOM detected prior to this routine */
|
|
if destIfFalse == destIfNull {
|
|
v1 = uintptr(0)
|
|
} else {
|
|
v1 = bp
|
|
}
|
|
eType = _sqlite3FindInIndex(tls, pParse, pExpr, libc.Uint32FromInt32(libc.Int32FromInt32(IN_INDEX_MEMBERSHIP)|libc.Int32FromInt32(IN_INDEX_NOOP_OK)), v1, aiMap, bp+8)
|
|
/* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a
|
|
** vector, then it is stored in an array of nVector registers starting
|
|
** at r1.
|
|
**
|
|
** sqlite3FindInIndex() might have reordered the fields of the LHS vector
|
|
** so that the fields are in the same order as an existing index. The
|
|
** aiMap[] array contains a mapping from the original LHS field order to
|
|
** the field order that matches the RHS index.
|
|
**
|
|
** Avoid factoring the LHS of the IN(...) expression out of the loop,
|
|
** even if it is constant, as OP_Affinity may be used on the register
|
|
** by code generated below. */
|
|
libc.SetBitFieldPtr16Uint32(pParse+40, libc.Uint32FromInt32(0), 7, 0x80)
|
|
rLhs = _exprCodeVector(tls, pParse, pLeft, bp+4)
|
|
libc.SetBitFieldPtr16Uint32(pParse+40, uint32(okConstFactor), 7, 0x80)
|
|
/* If sqlite3FindInIndex() did not find or create an index that is
|
|
** suitable for evaluating the IN operator, then evaluate using a
|
|
** sequence of comparisons.
|
|
**
|
|
** This is step (1) in the in-operator.md optimized algorithm.
|
|
*/
|
|
if eType == int32(IN_INDEX_NOOP) {
|
|
labelOk = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
regCkNull = 0
|
|
pList = *(*uintptr)(unsafe.Pointer(pExpr + 32))
|
|
pColl = _sqlite3ExprCollSeq(tls, pParse, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft)
|
|
if destIfNull != destIfFalse {
|
|
regCkNull = _sqlite3GetTempReg(tls, pParse)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_BitAnd), rLhs, rLhs, regCkNull)
|
|
}
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
r2 = _sqlite3ExprCodeTemp(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(ii)*32))).FpExpr, bp+12)
|
|
if regCkNull != 0 && _sqlite3ExprCanBeNull(tls, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(ii)*32))).FpExpr) != 0 {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_BitAnd), regCkNull, r2, regCkNull)
|
|
}
|
|
_sqlite3ReleaseTempReg(tls, pParse, **(**int32)(__ccgo_up(bp + 12)))
|
|
if ii < (*TExprList)(unsafe.Pointer(pList)).FnExpr-int32(1) || destIfNull != destIfFalse {
|
|
if rLhs != r2 {
|
|
v3 = int32(OP_Eq)
|
|
} else {
|
|
v3 = int32(OP_NotNull)
|
|
}
|
|
op = v3
|
|
_sqlite3VdbeAddOp4(tls, v, op, rLhs, labelOk, r2, pColl, -int32(2))
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(**(**uint8)(__ccgo_up(zAff))))
|
|
} else {
|
|
if rLhs != r2 {
|
|
v3 = int32(OP_Ne)
|
|
} else {
|
|
v3 = int32(OP_IsNull)
|
|
}
|
|
op1 = v3
|
|
_sqlite3VdbeAddOp4(tls, v, op1, rLhs, destIfFalse, r2, pColl, -int32(2))
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(zAff)))|int32(SQLITE_JUMPIFNULL)))
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if regCkNull != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IsNull), regCkNull, destIfNull)
|
|
_sqlite3VdbeGoto(tls, v, destIfFalse)
|
|
}
|
|
_sqlite3VdbeResolveLabel(tls, v, labelOk)
|
|
_sqlite3ReleaseTempReg(tls, pParse, regCkNull)
|
|
goto sqlite3ExprCodeIN_finished
|
|
}
|
|
if eType != int32(IN_INDEX_ROWID) {
|
|
/* If this IN operator will use an index, then the order of columns in the
|
|
** vector might be different from the order in the index. In that case,
|
|
** we need to reorder the LHS values to be in index order. Run Affinity
|
|
** before reordering the columns, so that the affinity is correct.
|
|
*/
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_Affinity), rLhs, nVector, 0, zAff, nVector)
|
|
i = 0
|
|
for {
|
|
if !(i < nVector && **(**int32)(__ccgo_up(aiMap + uintptr(i)*4)) == i) {
|
|
break
|
|
}
|
|
goto _5
|
|
_5:
|
|
;
|
|
i = i + 1
|
|
} /* Are LHS fields reordered? */
|
|
if i != nVector {
|
|
/* Need to reorder the LHS fields according to aiMap */
|
|
rLhsOrig = rLhs
|
|
rLhs = _sqlite3GetTempRange(tls, pParse, nVector)
|
|
i = 0
|
|
for {
|
|
if !(i < nVector) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Copy), rLhsOrig+i, rLhs+**(**int32)(__ccgo_up(aiMap + uintptr(i)*4)), 0)
|
|
goto _6
|
|
_6:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3ReleaseTempReg(tls, pParse, rLhsOrig)
|
|
}
|
|
}
|
|
/* Step 2: Check to see if the LHS contains any NULL columns. If the
|
|
** LHS does contain NULLs then the result must be either FALSE or NULL.
|
|
** We will then skip the binary search of the RHS.
|
|
*/
|
|
if destIfNull == destIfFalse {
|
|
destStep2 = destIfFalse
|
|
} else {
|
|
v3 = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
destStep6 = v3
|
|
destStep2 = v3
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < nVector) {
|
|
break
|
|
}
|
|
p = _sqlite3VectorFieldSubexpr(tls, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, i)
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
goto sqlite3ExprCodeIN_oom_error
|
|
}
|
|
if _sqlite3ExprCanBeNull(tls, p) != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IsNull), rLhs+**(**int32)(__ccgo_up(aiMap + uintptr(i)*4)), destStep2)
|
|
}
|
|
goto _8
|
|
_8:
|
|
;
|
|
i = i + 1
|
|
}
|
|
/* Step 3. The LHS is now known to be non-NULL. Do the binary search
|
|
** of the RHS using the LHS as a probe. If found, the result is
|
|
** true.
|
|
*/
|
|
if eType == int32(IN_INDEX_ROWID) {
|
|
/* In this case, the RHS is the ROWID of table b-tree and so we also
|
|
** know that the RHS is non-NULL. Hence, we combine steps 3 and 4
|
|
** into a single opcode. */
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_SeekRowid), **(**int32)(__ccgo_up(bp + 8)), destIfFalse, rLhs)
|
|
addrTruthOp = _sqlite3VdbeAddOp0(tls, v, int32(OP_Goto)) /* Return True */
|
|
} else {
|
|
if destIfFalse == destIfNull {
|
|
/* Combine Step 3 and Step 5 into a single opcode */
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subrtn)) != uint32(0) {
|
|
pOp = _sqlite3VdbeGetOp(tls, v, (*(*struct {
|
|
FiAddr int32
|
|
FregReturn int32
|
|
})(unsafe.Pointer(pExpr + 64))).FiAddr)
|
|
if (*TVdbeOp)(unsafe.Pointer(pOp)).Fp3 > 0 { /* tag-202407032019 */
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_Filter), (*TVdbeOp)(unsafe.Pointer(pOp)).Fp3, destIfFalse, rLhs, nVector)
|
|
}
|
|
}
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_NotFound), **(**int32)(__ccgo_up(bp + 8)), destIfFalse, rLhs, nVector)
|
|
goto sqlite3ExprCodeIN_finished
|
|
}
|
|
/* Ordinary Step 3, for the case where FALSE and NULL are distinct */
|
|
addrTruthOp = _sqlite3VdbeAddOp4Int(tls, v, int32(OP_Found), **(**int32)(__ccgo_up(bp + 8)), 0, rLhs, nVector)
|
|
}
|
|
/* Step 4. If the RHS is known to be non-NULL and we did not find
|
|
** an match on the search above, then the result must be FALSE.
|
|
*/
|
|
if **(**int32)(__ccgo_up(bp)) != 0 && nVector == int32(1) {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_NotNull), **(**int32)(__ccgo_up(bp)), destIfFalse)
|
|
}
|
|
/* Step 5. If we do not care about the difference between NULL and
|
|
** FALSE, then just return false.
|
|
*/
|
|
if destIfFalse == destIfNull {
|
|
_sqlite3VdbeGoto(tls, v, destIfFalse)
|
|
}
|
|
/* Step 6: Loop through rows of the RHS. Compare each row to the LHS.
|
|
** If any comparison is NULL, then the result is NULL. If all
|
|
** comparisons are FALSE then the final result is FALSE.
|
|
**
|
|
** For a scalar LHS, it is sufficient to check just the first row
|
|
** of the RHS.
|
|
*/
|
|
if destStep6 != 0 {
|
|
_sqlite3VdbeResolveLabel(tls, v, destStep6)
|
|
}
|
|
addrTop = _sqlite3VdbeAddOp2(tls, v, int32(OP_Rewind), **(**int32)(__ccgo_up(bp + 8)), destIfFalse)
|
|
if nVector > int32(1) {
|
|
destNotNull = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
} else {
|
|
/* For nVector==1, combine steps 6 and 7 by immediately returning
|
|
** FALSE if the first comparison is not NULL */
|
|
destNotNull = destIfFalse
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < nVector) {
|
|
break
|
|
}
|
|
r3 = _sqlite3GetTempReg(tls, pParse)
|
|
p1 = _sqlite3VectorFieldSubexpr(tls, pLeft, i)
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
pRhs = (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FpEList + 8 + uintptr(i)*32))).FpExpr
|
|
pColl1 = _sqlite3BinaryCompareCollSeq(tls, pParse, p1, pRhs)
|
|
} else {
|
|
/* If the RHS of the IN(...) expression are scalar expressions, do
|
|
** not consider their collation sequences. The documentation says
|
|
** "The collating sequence used for expressions of the form "x IN (y, z,
|
|
** ...)" is the collating sequence of x.". */
|
|
pColl1 = _sqlite3ExprCollSeq(tls, pParse, p1)
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), **(**int32)(__ccgo_up(bp + 8)), **(**int32)(__ccgo_up(aiMap + uintptr(i)*4)), r3)
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_Ne), rLhs+**(**int32)(__ccgo_up(aiMap + uintptr(i)*4)), destNotNull, r3, pColl1, -int32(2))
|
|
_sqlite3ReleaseTempReg(tls, pParse, r3)
|
|
goto _9
|
|
_9:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Goto), 0, destIfNull)
|
|
if nVector > int32(1) {
|
|
_sqlite3VdbeResolveLabel(tls, v, destNotNull)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), **(**int32)(__ccgo_up(bp + 8)), addrTop+int32(1))
|
|
/* Step 7: If we reach this point, we know that the result must
|
|
** be false. */
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Goto), 0, destIfFalse)
|
|
}
|
|
/* Jumps here in order to return true. */
|
|
_sqlite3VdbeJumpHere(tls, v, addrTruthOp)
|
|
goto sqlite3ExprCodeIN_finished
|
|
sqlite3ExprCodeIN_finished:
|
|
;
|
|
goto sqlite3ExprCodeIN_oom_error
|
|
sqlite3ExprCodeIN_oom_error:
|
|
;
|
|
_sqlite3DbFree(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, aiMap)
|
|
_sqlite3DbFree(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, zAff)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the collation sequence for the expression pExpr. If
|
|
// ** there is no defined collating sequence, return NULL.
|
|
// **
|
|
// ** See also: sqlite3ExprNNCollSeq()
|
|
// **
|
|
// ** The sqlite3ExprNNCollSeq() works the same exact that it returns the
|
|
// ** default collation if pExpr has no defined collation.
|
|
// **
|
|
// ** The collating sequence might be determined by a COLLATE operator
|
|
// ** or by the presence of a column with a defined collating sequence.
|
|
// ** COLLATE operators take first precedence. Left operands take
|
|
// ** precedence over right operands.
|
|
// */
|
|
func _sqlite3ExprCollSeq(tls *libc.TLS, pParse uintptr, pExpr uintptr) (r uintptr) {
|
|
var db, p, pColl, pNext, zColl uintptr
|
|
var i, j, op, v1 int32
|
|
_, _, _, _, _, _, _, _, _ = db, i, j, op, p, pColl, pNext, zColl, v1
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pColl = uintptr(0)
|
|
p = pExpr
|
|
for p != 0 {
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop)
|
|
if op == int32(TK_REGISTER) {
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop2)
|
|
}
|
|
if op == int32(TK_AGG_COLUMN) && *(*uintptr)(unsafe.Pointer(p + 64)) != uintptr(0) || op == int32(TK_COLUMN) || op == int32(TK_TRIGGER) {
|
|
v1 = int32((*TExpr)(unsafe.Pointer(p)).FiColumn)
|
|
j = v1
|
|
if v1 >= 0 {
|
|
zColl = _sqlite3ColumnColl(tls, (*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 64)))).FaCol+uintptr(j)*16)
|
|
pColl = _sqlite3FindCollSeq(tls, db, (*Tsqlite3)(unsafe.Pointer(db)).Fenc, zColl, 0)
|
|
}
|
|
break
|
|
}
|
|
if op == int32(TK_CAST) || op == int32(TK_UPLUS) {
|
|
p = (*TExpr)(unsafe.Pointer(p)).FpLeft
|
|
continue
|
|
}
|
|
if op == int32(TK_VECTOR) || op == int32(TK_FUNCTION) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).FaffExpr) == int32(SQLITE_AFF_DEFER) {
|
|
p = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 32)) + 8))).FpExpr
|
|
continue
|
|
}
|
|
if op == int32(TK_COLLATE) {
|
|
pColl = _sqlite3GetCollSeq(tls, pParse, (*Tsqlite3)(unsafe.Pointer(db)).Fenc, uintptr(0), *(*uintptr)(unsafe.Pointer(p + 8)))
|
|
break
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&uint32(EP_Collate) != 0 {
|
|
if (*TExpr)(unsafe.Pointer(p)).FpLeft != 0 && (*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(p)).FpLeft)).Fflags&uint32(EP_Collate) != uint32(0) {
|
|
p = (*TExpr)(unsafe.Pointer(p)).FpLeft
|
|
} else {
|
|
pNext = (*TExpr)(unsafe.Pointer(p)).FpRight
|
|
/* The Expr.x union is never used at the same time as Expr.pRight */
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&uint32(EP_xIsSelect) == uint32(0) && *(*uintptr)(unsafe.Pointer(p + 32)) != uintptr(0) && !((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0) {
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 32)))).FnExpr) {
|
|
break
|
|
}
|
|
if (*TExpr)(unsafe.Pointer((*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 32)) + 8 + uintptr(i)*32))).FpExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Collate)) != uint32(0) {
|
|
pNext = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 32)) + 8 + uintptr(i)*32))).FpExpr
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
p = pNext
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
if _sqlite3CheckCollSeq(tls, pParse, pColl) != 0 {
|
|
pColl = uintptr(0)
|
|
}
|
|
return pColl
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make a guess at all the possible datatypes of the result that could
|
|
// ** be returned by an expression. Return a bitmask indicating the answer:
|
|
// **
|
|
// ** 0x01 Numeric
|
|
// ** 0x02 Text
|
|
// ** 0x04 Blob
|
|
// **
|
|
// ** If the expression must return NULL, then 0x00 is returned.
|
|
// */
|
|
func _sqlite3ExprDataType(tls *libc.TLS, pExpr uintptr) (r int32) {
|
|
var aff, ii, res int32
|
|
var pList uintptr
|
|
_, _, _, _ = aff, ii, pList, res
|
|
for pExpr != 0 {
|
|
switch libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) {
|
|
case int32(TK_COLLATE):
|
|
fallthrough
|
|
case int32(TK_IF_NULL_ROW):
|
|
fallthrough
|
|
case int32(TK_UPLUS):
|
|
pExpr = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
case int32(TK_NULL):
|
|
pExpr = uintptr(0)
|
|
case int32(TK_STRING):
|
|
return int32(0x02)
|
|
case int32(TK_BLOB):
|
|
return int32(0x04)
|
|
case int32(TK_CONCAT):
|
|
return int32(0x06)
|
|
case int32(TK_VARIABLE):
|
|
fallthrough
|
|
case int32(TK_AGG_FUNCTION):
|
|
fallthrough
|
|
case int32(TK_FUNCTION):
|
|
return int32(0x07)
|
|
case int32(TK_COLUMN):
|
|
fallthrough
|
|
case int32(TK_AGG_COLUMN):
|
|
fallthrough
|
|
case int32(TK_SELECT):
|
|
fallthrough
|
|
case int32(TK_CAST):
|
|
fallthrough
|
|
case int32(TK_SELECT_COLUMN):
|
|
fallthrough
|
|
case int32(TK_VECTOR):
|
|
aff = libc.Int32FromUint8(_sqlite3ExprAffinity(tls, pExpr))
|
|
if aff >= int32(SQLITE_AFF_NUMERIC) {
|
|
return int32(0x05)
|
|
}
|
|
if aff == int32(SQLITE_AFF_TEXT) {
|
|
return int32(0x06)
|
|
}
|
|
return int32(0x07)
|
|
case int32(TK_CASE):
|
|
res = 0
|
|
pList = *(*uintptr)(unsafe.Pointer(pExpr + 32))
|
|
ii = int32(1)
|
|
for {
|
|
if !(ii < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
res = res | _sqlite3ExprDataType(tls, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(ii)*32))).FpExpr)
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + int32(2)
|
|
}
|
|
if (*TExprList)(unsafe.Pointer(pList)).FnExpr%int32(2) != 0 {
|
|
res = res | _sqlite3ExprDataType(tls, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr((*TExprList)(unsafe.Pointer(pList)).FnExpr-int32(1))*32))).FpExpr)
|
|
}
|
|
return res
|
|
default:
|
|
return int32(0x01)
|
|
} /* End of switch(op) */
|
|
} /* End of while(pExpr) */
|
|
return 0x00
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the expression is one of the following:
|
|
// **
|
|
// ** CASE WHEN x THEN y END
|
|
// ** CASE WHEN x THEN y ELSE NULL END
|
|
// ** CASE WHEN x THEN y ELSE false END
|
|
// ** iif(x,y)
|
|
// ** iif(x,y,NULL)
|
|
// ** iif(x,y,false)
|
|
// */
|
|
func _sqlite3ExprIsIIF(tls *libc.TLS, db uintptr, pExpr uintptr) (r int32) {
|
|
var pDef, pList, z uintptr
|
|
_, _, _ = pDef, pList, z
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_FUNCTION) {
|
|
z = *(*uintptr)(unsafe.Pointer(pExpr + 8))
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) != int32('i') && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) != int32('I') {
|
|
return 0
|
|
}
|
|
if *(*uintptr)(unsafe.Pointer(pExpr + 32)) == uintptr(0) {
|
|
return 0
|
|
}
|
|
pDef = _sqlite3FindFunction(tls, db, z, (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FnExpr, (*Tsqlite3)(unsafe.Pointer(db)).Fenc, uint8(0))
|
|
if pDef == uintptr(0) {
|
|
return 0
|
|
}
|
|
if (*TFuncDef)(unsafe.Pointer(pDef)).FfuncFlags&uint32(SQLITE_FUNC_INLINE) == uint32(0) {
|
|
return 0
|
|
}
|
|
if int32(int64((*TFuncDef)(unsafe.Pointer(pDef)).FpUserData)) != int32(INLINEFUNC_iif) {
|
|
return 0
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_CASE) {
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FpLeft != uintptr(0) {
|
|
return 0
|
|
}
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
pList = *(*uintptr)(unsafe.Pointer(pExpr + 32))
|
|
if (*TExprList)(unsafe.Pointer(pList)).FnExpr == int32(2) {
|
|
return int32(1)
|
|
}
|
|
if (*TExprList)(unsafe.Pointer(pList)).FnExpr == int32(3) && _sqlite3ExprIsNotTrue(tls, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + 2*32))).FpExpr) != 0 {
|
|
return int32(1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Locate a user function given a name, a number of arguments and a flag
|
|
// ** indicating whether the function prefers UTF-16 over UTF-8. Return a
|
|
// ** pointer to the FuncDef structure that defines that function, or return
|
|
// ** NULL if the function does not exist.
|
|
// **
|
|
// ** If the createFlag argument is true, then a new (blank) FuncDef
|
|
// ** structure is created and liked into the "db" structure if a
|
|
// ** no matching function previously existed.
|
|
// **
|
|
// ** If nArg is -2, then the first valid function found is returned. A
|
|
// ** function is valid if xSFunc is non-zero. The nArg==(-2)
|
|
// ** case is used to see if zName is a valid function name for some number
|
|
// ** of arguments. If nArg is -2, then createFlag must be 0.
|
|
// **
|
|
// ** If createFlag is false, then a function with the required name and
|
|
// ** number of arguments may be returned even if the eTextRep flag does not
|
|
// ** match that requested.
|
|
// */
|
|
func _sqlite3FindFunction(tls *libc.TLS, db uintptr, zName uintptr, nArg int32, enc Tu8, createFlag Tu8) (r uintptr) {
|
|
var bestScore, h, nName, score, score1 int32
|
|
var p, pBest, pOther, z, v1 uintptr
|
|
var v2 bool
|
|
_, _, _, _, _, _, _, _, _, _, _ = bestScore, h, nName, p, pBest, pOther, score, score1, z, v1, v2 /* Iterator variable */
|
|
pBest = uintptr(0) /* Best match found so far */
|
|
bestScore = 0 /* Length of the name */
|
|
nName = _sqlite3Strlen30(tls, zName)
|
|
/* First search for a match amongst the application-defined functions.
|
|
*/
|
|
p = _sqlite3HashFind(tls, db+624, zName)
|
|
for p != 0 {
|
|
score = _matchQuality(tls, p, nArg, enc)
|
|
if score > bestScore {
|
|
pBest = p
|
|
bestScore = score
|
|
}
|
|
p = (*TFuncDef)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
/* If no match is found, search the built-in functions.
|
|
**
|
|
** If the DBFLAG_PreferBuiltin flag is set, then search the built-in
|
|
** functions even if a prior app-defined function was found. And give
|
|
** priority to built-in functions.
|
|
**
|
|
** Except, if createFlag is true, that means that we are trying to
|
|
** install a new function. Whatever FuncDef structure is returned it will
|
|
** have fields overwritten with new information appropriate for the
|
|
** new function. But the FuncDefs for built-in functions are read-only.
|
|
** So we must not search for built-ins when creating a new function.
|
|
*/
|
|
if !(createFlag != 0) && (pBest == uintptr(0) || (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_PreferBuiltin) != uint32(0)) {
|
|
bestScore = 0
|
|
h = (libc.Int32FromUint8(_sqlite3UpperToLower[uint8(**(**uint8)(__ccgo_up(zName)))]) + nName) % int32(SQLITE_FUNC_HASH_SZ)
|
|
p = _sqlite3FunctionSearch(tls, h, zName)
|
|
for p != 0 {
|
|
score1 = _matchQuality(tls, p, nArg, enc)
|
|
if score1 > bestScore {
|
|
pBest = p
|
|
bestScore = score1
|
|
}
|
|
p = (*TFuncDef)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
}
|
|
/* If the createFlag parameter is true and the search did not reveal an
|
|
** exact match for the name, number of arguments and encoding, then add a
|
|
** new entry to the hash table and return it.
|
|
*/
|
|
if v2 = createFlag != 0 && bestScore < int32(FUNC_PERFECT_MATCH); v2 {
|
|
v1 = _sqlite3DbMallocZero(tls, db, uint64(uint64(72)+libc.Uint64FromInt32(nName)+uint64(1)))
|
|
pBest = v1
|
|
}
|
|
if v2 && v1 != uintptr(0) {
|
|
(*TFuncDef)(unsafe.Pointer(pBest)).FzName = pBest + 1*72
|
|
(*TFuncDef)(unsafe.Pointer(pBest)).FnArg = libc.Int16FromUint16(libc.Uint16FromInt32(nArg))
|
|
(*TFuncDef)(unsafe.Pointer(pBest)).FfuncFlags = uint32(enc)
|
|
libc.Xmemcpy(tls, pBest+1*72, zName, libc.Uint64FromInt32(nName+int32(1)))
|
|
z = (*TFuncDef)(unsafe.Pointer(pBest)).FzName
|
|
for {
|
|
if !(**(**Tu8)(__ccgo_up(z)) != 0) {
|
|
break
|
|
}
|
|
**(**Tu8)(__ccgo_up(z)) = _sqlite3UpperToLower[**(**Tu8)(__ccgo_up(z))]
|
|
goto _3
|
|
_3:
|
|
;
|
|
z = z + 1
|
|
}
|
|
pOther = _sqlite3HashInsert(tls, db+624, (*TFuncDef)(unsafe.Pointer(pBest)).FzName, pBest)
|
|
if pOther == pBest {
|
|
_sqlite3DbFree(tls, db, pBest)
|
|
_sqlite3OomFault(tls, db)
|
|
return uintptr(0)
|
|
} else {
|
|
(*TFuncDef)(unsafe.Pointer(pBest)).FpNext = pOther
|
|
}
|
|
}
|
|
if pBest != 0 && ((*TFuncDef)(unsafe.Pointer(pBest)).FxSFunc != 0 || createFlag != 0) {
|
|
return pBest
|
|
}
|
|
return uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Parameter zIn contains a rank() function specification. The format of
|
|
// ** this is:
|
|
// **
|
|
// ** + Bareword (function name)
|
|
// ** + Open parenthesis - "("
|
|
// ** + Zero or more SQL literals in a comma separated list
|
|
// ** + Close parenthesis - ")"
|
|
// */
|
|
func _sqlite3Fts5ConfigParseRank(tls *libc.TLS, zIn uintptr, pzRank uintptr, pzRankArgs uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var p, pArgs, pRank, zRank, zRankArgs uintptr
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _, _ = p, pArgs, pRank, zRank, zRankArgs
|
|
p = zIn
|
|
zRank = uintptr(0)
|
|
zRankArgs = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
**(**uintptr)(__ccgo_up(pzRank)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(pzRankArgs)) = uintptr(0)
|
|
if p == uintptr(0) {
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_ERROR)
|
|
} else {
|
|
p = _fts5ConfigSkipWhitespace(tls, p)
|
|
pRank = p
|
|
p = _fts5ConfigSkipBareword(tls, p)
|
|
if p != 0 {
|
|
zRank = _sqlite3Fts5MallocZero(tls, bp, int64(uintptr(1)+p)-int64(pRank))
|
|
if zRank != 0 {
|
|
libc.Xmemcpy(tls, zRank, pRank, libc.Uint64FromInt64(int64(p)-int64(pRank)))
|
|
}
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_ERROR)
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
p = _fts5ConfigSkipWhitespace(tls, p)
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(p))) != int32('(') {
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_ERROR)
|
|
}
|
|
p = p + 1
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
p = _fts5ConfigSkipWhitespace(tls, p)
|
|
pArgs = p
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(p))) != int32(')') {
|
|
p = _fts5ConfigSkipArgs(tls, p)
|
|
if p == uintptr(0) {
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_ERROR)
|
|
} else {
|
|
zRankArgs = _sqlite3Fts5MallocZero(tls, bp, int64(uintptr(1)+p)-int64(pArgs))
|
|
if zRankArgs != 0 {
|
|
libc.Xmemcpy(tls, zRankArgs, pArgs, libc.Uint64FromInt64(int64(p)-int64(pArgs)))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) != SQLITE_OK {
|
|
Xsqlite3_free(tls, zRank)
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(pzRank)) = zRank
|
|
**(**uintptr)(__ccgo_up(pzRankArgs)) = zRankArgs
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is only called when using the special 'trigram' tokenizer.
|
|
// ** Argument zText contains the text of a LIKE or GLOB pattern matched
|
|
// ** against column iCol. This function creates and compiles an FTS5 MATCH
|
|
// ** expression that will match a superset of the rows matched by the LIKE or
|
|
// ** GLOB. If successful, SQLITE_OK is returned. Otherwise, an SQLite error
|
|
// ** code.
|
|
// */
|
|
func _sqlite3Fts5ExprPattern(tls *libc.TLS, pConfig uintptr, bGlob int32, iCol int32, zText uintptr, pp uintptr) (r int32) {
|
|
var aSpec [3]uint8
|
|
var bAnd, i, iFirst, iOut, jj, rc, v1 int32
|
|
var nText Ti64
|
|
var zExpr uintptr
|
|
_, _, _, _, _, _, _, _, _, _ = aSpec, bAnd, i, iFirst, iOut, jj, nText, rc, zExpr, v1
|
|
nText = libc.Int64FromUint64(libc.Xstrlen(tls, zText))
|
|
zExpr = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(nText*int64(4)+int64(1)))
|
|
rc = SQLITE_OK
|
|
if zExpr == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
} else {
|
|
iOut = 0
|
|
i = 0
|
|
iFirst = 0
|
|
if bGlob == 0 {
|
|
aSpec[0] = uint8('_')
|
|
aSpec[int32(1)] = uint8('%')
|
|
aSpec[int32(2)] = uint8(0)
|
|
} else {
|
|
aSpec[0] = uint8('*')
|
|
aSpec[int32(1)] = uint8('?')
|
|
aSpec[int32(2)] = uint8('[')
|
|
}
|
|
for int64(i) <= nText {
|
|
if int64(i) == nText || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zText + uintptr(i)))) == libc.Int32FromUint8(aSpec[0]) || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zText + uintptr(i)))) == libc.Int32FromUint8(aSpec[int32(1)]) || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zText + uintptr(i)))) == libc.Int32FromUint8(aSpec[int32(2)]) {
|
|
if _fts5ExprCountChar(tls, zText+uintptr(iFirst), i-iFirst) >= int32(3) {
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**uint8)(__ccgo_up(zExpr + uintptr(v1))) = uint8('"')
|
|
jj = iFirst
|
|
for {
|
|
if !(jj < i) {
|
|
break
|
|
}
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**uint8)(__ccgo_up(zExpr + uintptr(v1))) = **(**uint8)(__ccgo_up(zText + uintptr(jj)))
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zText + uintptr(jj)))) == int32('"') {
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**uint8)(__ccgo_up(zExpr + uintptr(v1))) = uint8('"')
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
jj = jj + 1
|
|
}
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**uint8)(__ccgo_up(zExpr + uintptr(v1))) = uint8('"')
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**uint8)(__ccgo_up(zExpr + uintptr(v1))) = uint8(' ')
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zText + uintptr(i)))) == libc.Int32FromUint8(aSpec[int32(2)]) {
|
|
i = i + int32(2)
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zText + uintptr(i-int32(1))))) == int32('^') {
|
|
i = i + 1
|
|
}
|
|
for int64(i) < nText && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zText + uintptr(i)))) != int32(']') {
|
|
i = i + 1
|
|
}
|
|
}
|
|
iFirst = i + int32(1)
|
|
}
|
|
i = i + 1
|
|
}
|
|
if iOut > 0 {
|
|
bAnd = 0
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FeDetail != FTS5_DETAIL_FULL {
|
|
bAnd = int32(1)
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FeDetail == int32(FTS5_DETAIL_NONE) {
|
|
iCol = (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol
|
|
}
|
|
}
|
|
**(**uint8)(__ccgo_up(zExpr + uintptr(iOut))) = uint8('\000')
|
|
rc = _sqlite3Fts5ExprNew(tls, pConfig, bAnd, iCol, zExpr, pp, (*TFts5Config)(unsafe.Pointer(pConfig)).FpzErrmsg)
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(pp)) = uintptr(0)
|
|
}
|
|
Xsqlite3_free(tls, zExpr)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add an entry to the in-memory hash table. The key is the concatenation
|
|
// ** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos).
|
|
// **
|
|
// ** (bByte || pToken) -> (iRowid,iCol,iPos)
|
|
// **
|
|
// ** Or, if iCol is negative, then the value is a delete marker.
|
|
// */
|
|
func _sqlite3Fts5HashWrite(tls *libc.TLS, pHash uintptr, iRowid Ti64, iCol int32, iPos int32, bByte uint8, pToken uintptr, nToken int32) (r int32) {
|
|
var bNew, nIncr, rc, v2 int32
|
|
var iDiff Tu64
|
|
var iHash uint32
|
|
var nByte, nNew Tsqlite3_int64
|
|
var p, pNew, pPtr, pp, zKey, zKey1, v6 uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = bNew, iDiff, iHash, nByte, nIncr, nNew, p, pNew, pPtr, pp, rc, zKey, zKey1, v2, v6
|
|
nIncr = 0 /* If non-delete entry should be written */
|
|
bNew = libc.BoolInt32((*TFts5Hash)(unsafe.Pointer(pHash)).FeDetail == FTS5_DETAIL_FULL)
|
|
/* Attempt to locate an existing hash entry */
|
|
iHash = _fts5HashKey2(tls, (*TFts5Hash)(unsafe.Pointer(pHash)).FnSlot, bByte, pToken, nToken)
|
|
p = **(**uintptr)(__ccgo_up((*TFts5Hash)(unsafe.Pointer(pHash)).FaSlot + uintptr(iHash)*8))
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
zKey = p + 1*48
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zKey))) == libc.Int32FromUint8(bByte) && (*TFts5HashEntry)(unsafe.Pointer(p)).FnKey == nToken+int32(1) && libc.Xmemcmp(tls, zKey+1, pToken, libc.Uint64FromInt32(nToken)) == 0 {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TFts5HashEntry)(unsafe.Pointer(p)).FpHashNext
|
|
}
|
|
/* If an existing hash entry cannot be found, create a new one. */
|
|
if p == uintptr(0) {
|
|
nByte = libc.Int64FromUint64(uint64(48) + libc.Uint64FromInt32(nToken+libc.Int32FromInt32(1)) + uint64(1) + uint64(64))
|
|
if nByte < int64(128) {
|
|
nByte = int64(128)
|
|
}
|
|
/* Grow the Fts5Hash.aSlot[] array if necessary. */
|
|
if (*TFts5Hash)(unsafe.Pointer(pHash)).FnEntry*int32(2) >= (*TFts5Hash)(unsafe.Pointer(pHash)).FnSlot {
|
|
rc = _fts5HashResize(tls, pHash)
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
iHash = _fts5HashKey2(tls, (*TFts5Hash)(unsafe.Pointer(pHash)).FnSlot, bByte, pToken, nToken)
|
|
}
|
|
/* Allocate new Fts5HashEntry and add it to the hash table. */
|
|
p = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(nByte))
|
|
if !(p != 0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
libc.Xmemset(tls, p, 0, uint64(48))
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FnAlloc = int32(nByte)
|
|
zKey1 = p + 1*48
|
|
**(**uint8)(__ccgo_up(zKey1)) = bByte
|
|
libc.Xmemcpy(tls, zKey1+1, pToken, libc.Uint64FromInt32(nToken))
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FnKey = nToken + int32(1)
|
|
**(**uint8)(__ccgo_up(zKey1 + uintptr(nToken+int32(1)))) = uint8('\000')
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FnData = libc.Int32FromUint64(libc.Uint64FromInt32(nToken+int32(1)) + uint64(48))
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FpHashNext = **(**uintptr)(__ccgo_up((*TFts5Hash)(unsafe.Pointer(pHash)).FaSlot + uintptr(iHash)*8))
|
|
**(**uintptr)(__ccgo_up((*TFts5Hash)(unsafe.Pointer(pHash)).FaSlot + uintptr(iHash)*8)) = p
|
|
(*TFts5Hash)(unsafe.Pointer(pHash)).FnEntry = (*TFts5Hash)(unsafe.Pointer(pHash)).FnEntry + 1
|
|
/* Add the first rowid field to the hash-entry */
|
|
**(**int32)(__ccgo_up(p + 24)) += _sqlite3Fts5PutVarint(tls, p+uintptr((*TFts5HashEntry)(unsafe.Pointer(p)).FnData), libc.Uint64FromInt64(iRowid))
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiRowid = iRowid
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiSzPoslist = (*TFts5HashEntry)(unsafe.Pointer(p)).FnData
|
|
if (*TFts5Hash)(unsafe.Pointer(pHash)).FeDetail != int32(FTS5_DETAIL_NONE) {
|
|
**(**int32)(__ccgo_up(p + 24)) += int32(1)
|
|
if (*TFts5Hash)(unsafe.Pointer(pHash)).FeDetail == FTS5_DETAIL_FULL {
|
|
v2 = 0
|
|
} else {
|
|
v2 = -int32(1)
|
|
}
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiCol = int16(v2)
|
|
}
|
|
} else {
|
|
/* Appending to an existing hash-entry. Check that there is enough
|
|
** space to append the largest possible new entry. Worst case scenario
|
|
** is:
|
|
**
|
|
** + 9 bytes for a new rowid,
|
|
** + 4 byte reserved for the "poslist size" varint.
|
|
** + 1 byte for a "new column" byte,
|
|
** + 3 bytes for a new column number (16-bit max) as a varint,
|
|
** + 5 bytes for the new position offset (32-bit max).
|
|
*/
|
|
if (*TFts5HashEntry)(unsafe.Pointer(p)).FnAlloc-(*TFts5HashEntry)(unsafe.Pointer(p)).FnData < libc.Int32FromInt32(9)+libc.Int32FromInt32(4)+libc.Int32FromInt32(1)+libc.Int32FromInt32(3)+libc.Int32FromInt32(5) {
|
|
nNew = int64((*TFts5HashEntry)(unsafe.Pointer(p)).FnAlloc * int32(2))
|
|
pNew = Xsqlite3_realloc64(tls, p, libc.Uint64FromInt64(nNew))
|
|
if pNew == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TFts5HashEntry)(unsafe.Pointer(pNew)).FnAlloc = int32(nNew)
|
|
pp = (*TFts5Hash)(unsafe.Pointer(pHash)).FaSlot + uintptr(iHash)*8
|
|
for {
|
|
if !(**(**uintptr)(__ccgo_up(pp)) != p) {
|
|
break
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
pp = **(**uintptr)(__ccgo_up(pp))
|
|
}
|
|
**(**uintptr)(__ccgo_up(pp)) = pNew
|
|
p = pNew
|
|
}
|
|
nIncr = nIncr - (*TFts5HashEntry)(unsafe.Pointer(p)).FnData
|
|
}
|
|
pPtr = p
|
|
/* If this is a new rowid, append the 4-byte size field for the previous
|
|
** entry, and the new rowid for this entry. */
|
|
if iRowid != (*TFts5HashEntry)(unsafe.Pointer(p)).FiRowid {
|
|
iDiff = libc.Uint64FromInt64(iRowid) - libc.Uint64FromInt64((*TFts5HashEntry)(unsafe.Pointer(p)).FiRowid)
|
|
_fts5HashAddPoslistSize(tls, pHash, p, uintptr(0))
|
|
**(**int32)(__ccgo_up(p + 24)) += _sqlite3Fts5PutVarint(tls, pPtr+uintptr((*TFts5HashEntry)(unsafe.Pointer(p)).FnData), iDiff)
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiRowid = iRowid
|
|
bNew = int32(1)
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiSzPoslist = (*TFts5HashEntry)(unsafe.Pointer(p)).FnData
|
|
if (*TFts5Hash)(unsafe.Pointer(pHash)).FeDetail != int32(FTS5_DETAIL_NONE) {
|
|
**(**int32)(__ccgo_up(p + 24)) += int32(1)
|
|
if (*TFts5Hash)(unsafe.Pointer(pHash)).FeDetail == FTS5_DETAIL_FULL {
|
|
v2 = 0
|
|
} else {
|
|
v2 = -int32(1)
|
|
}
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiCol = int16(v2)
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiPos = 0
|
|
}
|
|
}
|
|
if iCol >= 0 {
|
|
if (*TFts5Hash)(unsafe.Pointer(pHash)).FeDetail == int32(FTS5_DETAIL_NONE) {
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FbContent = uint8(1)
|
|
} else {
|
|
/* Append a new column value, if necessary */
|
|
if iCol != int32((*TFts5HashEntry)(unsafe.Pointer(p)).FiCol) {
|
|
if (*TFts5Hash)(unsafe.Pointer(pHash)).FeDetail == FTS5_DETAIL_FULL {
|
|
v6 = p + 24
|
|
v2 = *(*int32)(unsafe.Pointer(v6))
|
|
*(*int32)(unsafe.Pointer(v6)) = *(*int32)(unsafe.Pointer(v6)) + 1
|
|
**(**Tu8)(__ccgo_up(pPtr + uintptr(v2))) = uint8(0x01)
|
|
**(**int32)(__ccgo_up(p + 24)) += _sqlite3Fts5PutVarint(tls, pPtr+uintptr((*TFts5HashEntry)(unsafe.Pointer(p)).FnData), libc.Uint64FromInt32(iCol))
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiCol = int16(iCol)
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiPos = 0
|
|
} else {
|
|
bNew = int32(1)
|
|
v2 = iCol
|
|
iPos = v2
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiCol = int16(v2)
|
|
}
|
|
}
|
|
/* Append the new position offset, if necessary */
|
|
if bNew != 0 {
|
|
**(**int32)(__ccgo_up(p + 24)) += _sqlite3Fts5PutVarint(tls, pPtr+uintptr((*TFts5HashEntry)(unsafe.Pointer(p)).FnData), libc.Uint64FromInt32(iPos-(*TFts5HashEntry)(unsafe.Pointer(p)).FiPos+int32(2)))
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FiPos = iPos
|
|
}
|
|
}
|
|
} else {
|
|
/* This is a delete. Set the delete flag. */
|
|
(*TFts5HashEntry)(unsafe.Pointer(p)).FbDel = uint8(1)
|
|
}
|
|
nIncr = nIncr + (*TFts5HashEntry)(unsafe.Pointer(p)).FnData
|
|
**(**int32)(__ccgo_up((*TFts5Hash)(unsafe.Pointer(pHash)).FpnByte)) += nIncr
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return a nul-terminated copy of the string indicated by pIn. If nIn
|
|
// ** is non-negative, then it is the length of the string in bytes. Otherwise,
|
|
// ** the length of the string is determined using strlen().
|
|
// **
|
|
// ** It is the responsibility of the caller to eventually free the returned
|
|
// ** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned.
|
|
// */
|
|
func _sqlite3Fts5Strndup(tls *libc.TLS, pRc uintptr, pIn uintptr, nIn int32) (r uintptr) {
|
|
var zRet uintptr
|
|
_ = zRet
|
|
zRet = uintptr(0)
|
|
if **(**int32)(__ccgo_up(pRc)) == SQLITE_OK {
|
|
if nIn < 0 {
|
|
nIn = libc.Int32FromUint64(libc.Xstrlen(tls, pIn))
|
|
}
|
|
zRet = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(int64(nIn)+int64(1)))
|
|
if zRet != 0 {
|
|
libc.Xmemcpy(tls, zRet, pIn, libc.Uint64FromInt32(nIn))
|
|
**(**uint8)(__ccgo_up(zRet + uintptr(nIn))) = uint8('\000')
|
|
} else {
|
|
**(**int32)(__ccgo_up(pRc)) = int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
return zRet
|
|
}
|
|
|
|
func _sqlite3Fts5TermsetAdd(tls *libc.TLS, p uintptr, iIdx int32, pTerm uintptr, nTerm int32, pbPresent uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var hash Tu32
|
|
var i int32
|
|
var pEntry uintptr
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _ = hash, i, pEntry
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
**(**int32)(__ccgo_up(pbPresent)) = 0
|
|
if p != 0 {
|
|
hash = uint32(13)
|
|
/* Calculate a hash value for this term. This is the same hash checksum
|
|
** used by the fts5_hash.c module. This is not important for correct
|
|
** operation of the module, but is necessary to ensure that some tests
|
|
** designed to produce hash table collisions really do work. */
|
|
i = nTerm - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
hash = hash<<libc.Int32FromInt32(3) ^ hash ^ uint32(**(**uint8)(__ccgo_up(pTerm + uintptr(i))))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
hash = hash<<libc.Int32FromInt32(3) ^ hash ^ libc.Uint32FromInt32(iIdx)
|
|
hash = hash % libc.Uint32FromInt32(libc.Int32FromUint64(libc.Uint64FromInt64(4096)/libc.Uint64FromInt64(8)))
|
|
pEntry = **(**uintptr)(__ccgo_up(p + uintptr(hash)*8))
|
|
for {
|
|
if !(pEntry != 0) {
|
|
break
|
|
}
|
|
if (*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FiIdx == iIdx && (*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FnTerm == nTerm && libc.Xmemcmp(tls, (*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FpTerm, pTerm, libc.Uint64FromInt32(nTerm)) == 0 {
|
|
**(**int32)(__ccgo_up(pbPresent)) = int32(1)
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pEntry = (*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FpNext
|
|
}
|
|
if pEntry == uintptr(0) {
|
|
pEntry = _sqlite3Fts5MallocZero(tls, bp, libc.Int64FromUint64(uint64(24)+libc.Uint64FromInt32(nTerm)))
|
|
if pEntry != 0 {
|
|
(*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FpTerm = pEntry + 1*24
|
|
(*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FnTerm = nTerm
|
|
(*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FiIdx = iIdx
|
|
libc.Xmemcpy(tls, (*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FpTerm, pTerm, libc.Uint64FromInt32(nTerm))
|
|
(*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FpNext = **(**uintptr)(__ccgo_up(p + uintptr(hash)*8))
|
|
**(**uintptr)(__ccgo_up(p + uintptr(hash)*8)) = pEntry
|
|
}
|
|
}
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If zNum represents an integer that will fit in 32-bits, then set
|
|
// ** *pValue to that integer and return true. Otherwise return false.
|
|
// **
|
|
// ** This routine accepts both decimal and hexadecimal notation for integers.
|
|
// **
|
|
// ** Any non-numeric characters that following zNum are ignored.
|
|
// ** This is different from sqlite3Atoi64() which requires the
|
|
// ** input number to be zero-terminated.
|
|
// */
|
|
func _sqlite3GetInt32(tls *libc.TLS, zNum uintptr, pValue uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var c, i, neg, v3 int32
|
|
var v Tsqlite_int64
|
|
var v4 bool
|
|
var _ /* u at bp+0 */ Tu32
|
|
_, _, _, _, _, _ = c, i, neg, v, v3, v4
|
|
v = 0
|
|
neg = 0
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum))) == int32('-') {
|
|
neg = int32(1)
|
|
zNum = zNum + 1
|
|
} else {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum))) == int32('+') {
|
|
zNum = zNum + 1
|
|
} else {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum))) == int32('0') && (libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum + 1))) == int32('x') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum + 1))) == int32('X')) && libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(zNum + 2)))])&int32(0x08) != 0 {
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
zNum = zNum + uintptr(2)
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum))) == int32('0') {
|
|
zNum = zNum + 1
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < int32(8) && libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(zNum + uintptr(i))))])&int32(0x08) != 0) {
|
|
break
|
|
}
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp))*uint32(16) + uint32(_sqlite3HexToInt(tls, libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum + uintptr(i))))))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp))&uint32(0x80000000) == uint32(0) && libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(zNum + uintptr(i))))])&int32(0x08) == 0 {
|
|
libc.Xmemcpy(tls, pValue, bp, uint64(4))
|
|
return int32(1)
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if !(libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(zNum)))])&libc.Int32FromInt32(0x04) != 0) {
|
|
return 0
|
|
}
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum))) == int32('0') {
|
|
zNum = zNum + 1
|
|
}
|
|
i = 0
|
|
for {
|
|
if v4 = i < int32(11); v4 {
|
|
v3 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(zNum + uintptr(i)))) - libc.Int32FromUint8('0')
|
|
c = v3
|
|
}
|
|
if !(v4 && v3 >= 0 && c <= int32(9)) {
|
|
break
|
|
}
|
|
v = v*int64(10) + int64(c)
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
/* The longest decimal representation of a 32 bit integer is 10 digits:
|
|
**
|
|
** 1234567890
|
|
** 2^31 -> 2147483648
|
|
*/
|
|
if i > int32(10) {
|
|
return 0
|
|
}
|
|
if v-int64(neg) > int64(2147483647) {
|
|
return 0
|
|
}
|
|
if neg != 0 {
|
|
v = -v
|
|
}
|
|
**(**int32)(__ccgo_up(pValue)) = int32(v)
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Insert a new FuncDef into a FuncDefHash hash table.
|
|
// */
|
|
func _sqlite3InsertBuiltinFuncs(tls *libc.TLS, aDef uintptr, nDef int32) {
|
|
var h, i, nName int32
|
|
var pOther, zName uintptr
|
|
_, _, _, _, _ = h, i, nName, pOther, zName
|
|
i = 0
|
|
for {
|
|
if !(i < nDef) {
|
|
break
|
|
}
|
|
zName = (**(**TFuncDef)(__ccgo_up(aDef + uintptr(i)*72))).FzName
|
|
nName = _sqlite3Strlen30(tls, zName)
|
|
h = (libc.Int32FromUint8(**(**uint8)(__ccgo_up(zName))) + nName) % int32(SQLITE_FUNC_HASH_SZ)
|
|
pOther = _sqlite3FunctionSearch(tls, h, zName)
|
|
if pOther != 0 {
|
|
(**(**TFuncDef)(__ccgo_up(aDef + uintptr(i)*72))).FpNext = (*TFuncDef)(unsafe.Pointer(pOther)).FpNext
|
|
(*TFuncDef)(unsafe.Pointer(pOther)).FpNext = aDef + uintptr(i)*72
|
|
} else {
|
|
(**(**TFuncDef)(__ccgo_up(aDef + uintptr(i)*72))).FpNext = uintptr(0)
|
|
*(*uintptr)(unsafe.Pointer(aDef + uintptr(i)*72 + 64)) = **(**uintptr)(__ccgo_up(uintptr(unsafe.Pointer(&_sqlite3BuiltinFunctions)) + uintptr(h)*8))
|
|
**(**uintptr)(__ccgo_up(uintptr(unsafe.Pointer(&_sqlite3BuiltinFunctions)) + uintptr(h)*8)) = aDef + uintptr(i)*72
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Render an signed 64-bit integer as text. Store the result in zOut[] and
|
|
// ** return the length of the string that was stored, in bytes. The value
|
|
// ** returned does not include the zero terminator at the end of the output
|
|
// ** string.
|
|
// **
|
|
// ** The caller must ensure that zOut[] is at least 21 bytes in size.
|
|
// */
|
|
func _sqlite3Int64ToText(tls *libc.TLS, v Ti64, zOut uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var i, kk, v2 int32
|
|
var x Tu64
|
|
var v1 uint64
|
|
var _ /* u at bp+0 */ struct {
|
|
FforceAlignment [0]Tu16
|
|
Fa [21]uint8
|
|
F__ccgo_pad2 [1]byte
|
|
}
|
|
_, _, _, _, _ = i, kk, x, v1, v2
|
|
if v > 0 {
|
|
x = libc.Uint64FromInt64(v)
|
|
} else {
|
|
if v == 0 {
|
|
**(**uint8)(__ccgo_up(zOut)) = uint8('0')
|
|
**(**uint8)(__ccgo_up(zOut + 1)) = uint8(0)
|
|
return int32(1)
|
|
} else {
|
|
if v == int64(-libc.Int32FromInt32(1))-(libc.Int64FromUint32(0xffffffff)|libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32)) {
|
|
v1 = libc.Uint64FromInt32(1) << libc.Int32FromInt32(63)
|
|
} else {
|
|
v1 = libc.Uint64FromInt64(-v)
|
|
}
|
|
x = v1
|
|
}
|
|
}
|
|
i = libc.Int32FromUint64(libc.Uint64FromInt64(21) - libc.Uint64FromInt32(1))
|
|
**(**uint8)(__ccgo_up(bp + uintptr(i))) = uint8(0)
|
|
for x >= uint64(10) {
|
|
kk = libc.Int32FromUint64(x % uint64(100) * uint64(2))
|
|
**(**Tu16)(__ccgo_up(bp + uintptr(i-int32(2)))) = **(**Tu16)(__ccgo_up(uintptr(unsafe.Pointer(&_sqlite3DigitPairs)) + uintptr(kk)))
|
|
i = i - int32(2)
|
|
x = x / uint64(100)
|
|
}
|
|
if x != 0 {
|
|
i = i - 1
|
|
v2 = i
|
|
**(**uint8)(__ccgo_up(bp + uintptr(v2))) = uint8(x + uint64('0'))
|
|
}
|
|
if v < 0 {
|
|
i = i - 1
|
|
v2 = i
|
|
**(**uint8)(__ccgo_up(bp + uintptr(v2))) = uint8('-')
|
|
}
|
|
libc.Xmemcpy(tls, zOut, bp+uintptr(i), uint64(21)-libc.Uint64FromInt32(i))
|
|
return libc.Int32FromUint64(libc.Uint64FromInt64(21) - libc.Uint64FromInt32(1) - libc.Uint64FromInt32(i))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pExpr points to an expression which implements a function. If
|
|
// ** it is appropriate to apply the LIKE optimization to that function
|
|
// ** then set aWc[0] through aWc[2] to the wildcard characters and the
|
|
// ** escape character and then return TRUE. If the function is not a
|
|
// ** LIKE-style function then return FALSE.
|
|
// **
|
|
// ** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
|
|
// ** operator if c is a string literal that is exactly one byte in length.
|
|
// ** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is
|
|
// ** no ESCAPE clause.
|
|
// **
|
|
// ** *pIsNocase is set to true if uppercase and lowercase are equivalent for
|
|
// ** the function (default for LIKE). If the function makes the distinction
|
|
// ** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to
|
|
// ** false.
|
|
// */
|
|
func _sqlite3IsLikeFunction(tls *libc.TLS, db uintptr, pExpr uintptr, pIsNocase uintptr, aWc uintptr) (r int32) {
|
|
var nExpr int32
|
|
var pDef, pEscape, zEscape uintptr
|
|
_, _, _, _ = nExpr, pDef, pEscape, zEscape
|
|
if !(*(*uintptr)(unsafe.Pointer(pExpr + 32)) != 0) {
|
|
return 0
|
|
}
|
|
nExpr = (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FnExpr
|
|
pDef = _sqlite3FindFunction(tls, db, *(*uintptr)(unsafe.Pointer(pExpr + 8)), nExpr, uint8(SQLITE_UTF8), uint8(0))
|
|
if pDef == uintptr(0) || (*TFuncDef)(unsafe.Pointer(pDef)).FfuncFlags&uint32(SQLITE_FUNC_LIKE) == uint32(0) {
|
|
return 0
|
|
}
|
|
/* The memcpy() statement assumes that the wildcard characters are
|
|
** the first three statements in the compareInfo structure. The
|
|
** asserts() that follow verify that assumption
|
|
*/
|
|
libc.Xmemcpy(tls, aWc, (*TFuncDef)(unsafe.Pointer(pDef)).FpUserData, uint64(3))
|
|
if nExpr < int32(3) {
|
|
**(**uint8)(__ccgo_up(aWc + 3)) = uint8(0)
|
|
} else {
|
|
pEscape = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)) + 8 + 2*32))).FpExpr
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pEscape)).Fop) != int32(TK_STRING) {
|
|
return 0
|
|
}
|
|
zEscape = *(*uintptr)(unsafe.Pointer(pEscape + 8))
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zEscape))) == 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zEscape + 1))) != 0 {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zEscape))) == libc.Int32FromUint8(**(**uint8)(__ccgo_up(aWc))) {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zEscape))) == libc.Int32FromUint8(**(**uint8)(__ccgo_up(aWc + 1))) {
|
|
return 0
|
|
}
|
|
**(**uint8)(__ccgo_up(aWc + 3)) = **(**uint8)(__ccgo_up(zEscape))
|
|
}
|
|
**(**int32)(__ccgo_up(pIsNocase)) = libc.BoolInt32((*TFuncDef)(unsafe.Pointer(pDef)).FfuncFlags&uint32(SQLITE_FUNC_CASE) == uint32(0))
|
|
return int32(1)
|
|
}
|
|
|
|
/* Mathematical Constants */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if pTab is a virtual table and zName is a shadow table name
|
|
// ** for that virtual table.
|
|
// */
|
|
func _sqlite3IsShadowTableOf(tls *libc.TLS, db uintptr, pTab uintptr, zName uintptr) (r int32) {
|
|
var nName int32
|
|
var pMod uintptr
|
|
_, _ = nName, pMod /* Module for the virtual table */
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_VTAB)) {
|
|
return 0
|
|
}
|
|
nName = _sqlite3Strlen30(tls, (*TTable)(unsafe.Pointer(pTab)).FzName)
|
|
if Xsqlite3_strnicmp(tls, zName, (*TTable)(unsafe.Pointer(pTab)).FzName, nName) != 0 {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(zName + uintptr(nName)))) != int32('_') {
|
|
return 0
|
|
}
|
|
pMod = _sqlite3HashFind(tls, db+576, **(**uintptr)(__ccgo_up((*(*struct {
|
|
FnArg int32
|
|
FazArg uintptr
|
|
Fp uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FazArg)))
|
|
if pMod == uintptr(0) {
|
|
return 0
|
|
}
|
|
if (*Tsqlite3_module)(unsafe.Pointer((*TModule)(unsafe.Pointer(pMod)).FpModule)).FiVersion < int32(3) {
|
|
return 0
|
|
}
|
|
if (*Tsqlite3_module)(unsafe.Pointer((*TModule)(unsafe.Pointer(pMod)).FpModule)).FxShadowName == uintptr(0) {
|
|
return 0
|
|
}
|
|
return (*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3_module)(unsafe.Pointer((*TModule)(unsafe.Pointer(pMod)).FpModule)).FxShadowName})))(tls, zName+uintptr(nName)+uintptr(1))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Table pTab is a virtual table. If it the virtual table implementation
|
|
// ** exists and has an xShadowName method, then loop over all other ordinary
|
|
// ** tables within the same schema looking for shadow tables of pTab, and mark
|
|
// ** any shadow tables seen using the TF_Shadow flag.
|
|
// */
|
|
func _sqlite3MarkAllShadowTablesOf(tls *libc.TLS, db uintptr, pTab uintptr) {
|
|
var k, pMod, pOther uintptr
|
|
var nName int32
|
|
_, _, _, _ = k, nName, pMod, pOther /* For looping through the symbol table */
|
|
pMod = _sqlite3HashFind(tls, db+576, **(**uintptr)(__ccgo_up((*(*struct {
|
|
FnArg int32
|
|
FazArg uintptr
|
|
Fp uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FazArg)))
|
|
if pMod == uintptr(0) {
|
|
return
|
|
}
|
|
if (*TModule)(unsafe.Pointer(pMod)).FpModule == uintptr(0) {
|
|
return
|
|
}
|
|
if (*Tsqlite3_module)(unsafe.Pointer((*TModule)(unsafe.Pointer(pMod)).FpModule)).FiVersion < int32(3) {
|
|
return
|
|
}
|
|
if (*Tsqlite3_module)(unsafe.Pointer((*TModule)(unsafe.Pointer(pMod)).FpModule)).FxShadowName == uintptr(0) {
|
|
return
|
|
}
|
|
nName = _sqlite3Strlen30(tls, (*TTable)(unsafe.Pointer(pTab)).FzName)
|
|
k = (*THash)(unsafe.Pointer((*TTable)(unsafe.Pointer(pTab)).FpSchema + 8)).Ffirst
|
|
for {
|
|
if !(k != 0) {
|
|
break
|
|
}
|
|
pOther = (*THashElem)(unsafe.Pointer(k)).Fdata
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pOther)).FeTabType) == libc.Int32FromInt32(TABTYP_NORM)) {
|
|
goto _1
|
|
}
|
|
if (*TTable)(unsafe.Pointer(pOther)).FtabFlags&uint32(TF_Shadow) != 0 {
|
|
goto _1
|
|
}
|
|
if Xsqlite3_strnicmp(tls, (*TTable)(unsafe.Pointer(pOther)).FzName, (*TTable)(unsafe.Pointer(pTab)).FzName, nName) == 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up((*TTable)(unsafe.Pointer(pOther)).FzName + uintptr(nName)))) == int32('_') && (*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3_module)(unsafe.Pointer((*TModule)(unsafe.Pointer(pMod)).FpModule)).FxShadowName})))(tls, (*TTable)(unsafe.Pointer(pOther)).FzName+uintptr(nName)+uintptr(1)) != 0 {
|
|
**(**Tu32)(__ccgo_up(pOther + 48)) |= uint32(TF_Shadow)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
k = (*THashElem)(unsafe.Pointer(k)).Fnext
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Subqueries store the original database, table and column names for their
|
|
// ** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN",
|
|
// ** and mark the expression-list item by setting ExprList.a[].fg.eEName
|
|
// ** to ENAME_TAB.
|
|
// **
|
|
// ** Check to see if the zSpan/eEName of the expression-list item passed to this
|
|
// ** routine matches the zDb, zTab, and zCol. If any of zDb, zTab, and zCol are
|
|
// ** NULL then those fields will match anything. Return true if there is a match,
|
|
// ** or false otherwise.
|
|
// **
|
|
// ** SF_NestedFrom subqueries also store an entry for the implicit rowid (or
|
|
// ** _rowid_, or oid) column by setting ExprList.a[].fg.eEName to ENAME_ROWID,
|
|
// ** and setting zSpan to "DATABASE.TABLE.<rowid-alias>". This type of pItem
|
|
// ** argument matches if zCol is a rowid alias. If it is not NULL, (*pbRowid)
|
|
// ** is set to 1 if there is this kind of match.
|
|
// */
|
|
func _sqlite3MatchEName(tls *libc.TLS, pItem uintptr, zCol uintptr, zTab uintptr, zDb uintptr, pbRowid uintptr) (r int32) {
|
|
var eEName, n int32
|
|
var zSpan uintptr
|
|
_, _, _ = eEName, n, zSpan
|
|
eEName = int32(uint32(*(*uint16)(unsafe.Pointer(pItem + 16 + 4)) & 0x3 >> 0))
|
|
if eEName != int32(ENAME_TAB) && (eEName != int32(ENAME_ROWID) || pbRowid == uintptr(0)) {
|
|
return 0
|
|
}
|
|
zSpan = (*TExprList_item)(unsafe.Pointer(pItem)).FzEName
|
|
n = 0
|
|
for {
|
|
if !(**(**uint8)(__ccgo_up(zSpan + uintptr(n))) != 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zSpan + uintptr(n)))) != int32('.')) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
n = n + 1
|
|
}
|
|
if zDb != 0 && (Xsqlite3_strnicmp(tls, zSpan, zDb, n) != 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zDb + uintptr(n)))) != 0) {
|
|
return 0
|
|
}
|
|
zSpan = zSpan + uintptr(n+int32(1))
|
|
n = 0
|
|
for {
|
|
if !(**(**uint8)(__ccgo_up(zSpan + uintptr(n))) != 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zSpan + uintptr(n)))) != int32('.')) {
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
n = n + 1
|
|
}
|
|
if zTab != 0 && (Xsqlite3_strnicmp(tls, zSpan, zTab, n) != 0 || libc.Int32FromUint8(**(**uint8)(__ccgo_up(zTab + uintptr(n)))) != 0) {
|
|
return 0
|
|
}
|
|
zSpan = zSpan + uintptr(n+int32(1))
|
|
if zCol != 0 {
|
|
if eEName == int32(ENAME_TAB) && _sqlite3StrICmp(tls, zSpan, zCol) != 0 {
|
|
return 0
|
|
}
|
|
if eEName == int32(ENAME_ROWID) && _sqlite3IsRowid(tls, zCol) == 0 {
|
|
return 0
|
|
}
|
|
}
|
|
if eEName == int32(ENAME_ROWID) {
|
|
**(**int32)(__ccgo_up(pbRowid)) = int32(1)
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Run the parser and code generator recursively in order to generate
|
|
// ** code for the SQL statement given onto the end of the pParse context
|
|
// ** currently under construction. Notes:
|
|
// **
|
|
// ** * The final OP_Halt is not appended and other initialization
|
|
// ** and finalization steps are omitted because those are handling by the
|
|
// ** outermost parser.
|
|
// **
|
|
// ** * Built-in SQL functions always take precedence over application-defined
|
|
// ** SQL functions. In other words, it is not possible to override a
|
|
// ** built-in function.
|
|
// */
|
|
func _sqlite3NestedParse(tls *libc.TLS, pParse uintptr, zFormat uintptr, va uintptr) {
|
|
bp := tls.Alloc(144)
|
|
defer tls.Free(144)
|
|
var ap Tva_list
|
|
var db, zSql uintptr
|
|
var savedDbFlags Tu32
|
|
var _ /* saveBuf at bp+0 */ [136]uint8
|
|
_, _, _, _ = ap, db, savedDbFlags, zSql
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
savedDbFlags = (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FeParseMode != 0 {
|
|
return
|
|
}
|
|
/* Nesting should only be of limited depth */
|
|
ap = va
|
|
zSql = _sqlite3VMPrintf(tls, db, zFormat, ap)
|
|
_ = ap
|
|
if zSql == uintptr(0) {
|
|
/* This can result either from an OOM or because the formatted string
|
|
** exceeds SQLITE_LIMIT_LENGTH. In the latter case, we need to set
|
|
** an error */
|
|
if !((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0) {
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_TOOBIG)
|
|
}
|
|
(*TParse)(unsafe.Pointer(pParse)).FnErr = (*TParse)(unsafe.Pointer(pParse)).FnErr + 1
|
|
return
|
|
}
|
|
(*TParse)(unsafe.Pointer(pParse)).Fnested = (*TParse)(unsafe.Pointer(pParse)).Fnested + 1
|
|
libc.Xmemcpy(tls, bp, pParse+uintptr(uint64(libc.UintptrFromInt32(0)+288)), libc.Uint64FromInt64(424)-uint64(libc.UintptrFromInt32(0)+288))
|
|
libc.Xmemset(tls, pParse+uintptr(uint64(libc.UintptrFromInt32(0)+288)), 0, libc.Uint64FromInt64(424)-uint64(libc.UintptrFromInt32(0)+288))
|
|
**(**Tu32)(__ccgo_up(db + 44)) |= uint32(DBFLAG_PreferBuiltin)
|
|
_sqlite3RunParser(tls, pParse, zSql)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags = savedDbFlags
|
|
_sqlite3DbFree(tls, db, zSql)
|
|
libc.Xmemcpy(tls, pParse+uintptr(uint64(libc.UintptrFromInt32(0)+288)), bp, libc.Uint64FromInt64(424)-uint64(libc.UintptrFromInt32(0)+288))
|
|
(*TParse)(unsafe.Pointer(pParse)).Fnested = (*TParse)(unsafe.Pointer(pParse)).Fnested - 1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is used to allocate and populate UnpackedRecord
|
|
// ** structures intended to be compared against sample index keys stored
|
|
// ** in the sqlite_stat4 table.
|
|
// **
|
|
// ** A single call to this function populates zero or more fields of the
|
|
// ** record starting with field iVal (fields are numbered from left to
|
|
// ** right starting with 0). A single field is populated if:
|
|
// **
|
|
// ** * (pExpr==0). In this case the value is assumed to be an SQL NULL,
|
|
// **
|
|
// ** * The expression is a bound variable, and this is a reprepare, or
|
|
// **
|
|
// ** * The sqlite3ValueFromExpr() function is able to extract a value
|
|
// ** from the expression (i.e. the expression is a literal value).
|
|
// **
|
|
// ** Or, if pExpr is a TK_VECTOR, one field is populated for each of the
|
|
// ** vector components that match either of the two latter criteria listed
|
|
// ** above.
|
|
// **
|
|
// ** Before any value is appended to the record, the affinity of the
|
|
// ** corresponding column within index pIdx is applied to it. Before
|
|
// ** this function returns, output parameter *pnExtract is set to the
|
|
// ** number of values appended to the record.
|
|
// **
|
|
// ** When this function is called, *ppRec must either point to an object
|
|
// ** allocated by an earlier call to this function, or must be NULL. If it
|
|
// ** is NULL and a value can be successfully extracted, a new UnpackedRecord
|
|
// ** is allocated (and *ppRec set to point to it) before returning.
|
|
// **
|
|
// ** Unless an error is encountered, SQLITE_OK is returned. It is not an
|
|
// ** error if a value cannot be extracted from pExpr. If an error does
|
|
// ** occur, an SQLite error code is returned.
|
|
// */
|
|
func _sqlite3Stat4ProbeSetValue(tls *libc.TLS, pParse uintptr, pIdx uintptr, ppRec uintptr, pExpr uintptr, nElem int32, iVal int32, pnExtract uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var aff Tu8
|
|
var i, nExtract, rc int32
|
|
var pElem, v2 uintptr
|
|
var _ /* alloc at bp+0 */ TValueNewStat4Ctx
|
|
var _ /* pVal at bp+32 */ uintptr
|
|
_, _, _, _, _, _ = aff, i, nExtract, pElem, rc, v2
|
|
rc = SQLITE_OK
|
|
nExtract = 0
|
|
if pExpr == uintptr(0) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_SELECT) {
|
|
(**(**TValueNewStat4Ctx)(__ccgo_up(bp))).FpParse = pParse
|
|
(**(**TValueNewStat4Ctx)(__ccgo_up(bp))).FpIdx = pIdx
|
|
(**(**TValueNewStat4Ctx)(__ccgo_up(bp))).FppRec = ppRec
|
|
i = 0
|
|
for {
|
|
if !(i < nElem) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp + 32)) = uintptr(0)
|
|
if pExpr != 0 {
|
|
v2 = _sqlite3VectorFieldSubexpr(tls, pExpr, i)
|
|
} else {
|
|
v2 = uintptr(0)
|
|
}
|
|
pElem = v2
|
|
aff = _sqlite3IndexColumnAffinity(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pIdx, iVal+i)
|
|
(**(**TValueNewStat4Ctx)(__ccgo_up(bp))).FiVal = iVal + i
|
|
rc = _stat4ValueFromExpr(tls, pParse, pElem, aff, bp, bp+32)
|
|
if !(**(**uintptr)(__ccgo_up(bp + 32)) != 0) {
|
|
break
|
|
}
|
|
nExtract = nExtract + 1
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
**(**int32)(__ccgo_up(pnExtract)) = nExtract
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute an affinity string for a table. Space is obtained
|
|
// ** from sqlite3DbMalloc(). The caller is responsible for freeing
|
|
// ** the space when done.
|
|
// */
|
|
func _sqlite3TableAffinityStr(tls *libc.TLS, db uintptr, pTab uintptr) (r uintptr) {
|
|
var i, j, v2, v3 int32
|
|
var zColAff uintptr
|
|
_, _, _, _, _ = i, j, zColAff, v2, v3
|
|
zColAff = _sqlite3DbMallocRaw(tls, db, libc.Uint64FromInt32(int32((*TTable)(unsafe.Pointer(pTab)).FnCol)+int32(1)))
|
|
if zColAff != 0 {
|
|
v2 = libc.Int32FromInt32(0)
|
|
j = v2
|
|
i = v2
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) == 0 {
|
|
v3 = j
|
|
j = j + 1
|
|
**(**uint8)(__ccgo_up(zColAff + uintptr(v3))) = (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16))).Faffinity
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
for cond := true; cond; cond = j >= 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zColAff + uintptr(j)))) <= int32(SQLITE_AFF_BLOB) {
|
|
v2 = j
|
|
j = j - 1
|
|
**(**uint8)(__ccgo_up(zColAff + uintptr(v2))) = uint8(0)
|
|
}
|
|
}
|
|
return zColAff
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the affinity character for a single column of a table.
|
|
// */
|
|
func _sqlite3TableColumnAffinity(tls *libc.TLS, pTab uintptr, iCol int32) (r uint8) {
|
|
if iCol < 0 || iCol >= int32((*TTable)(unsafe.Pointer(pTab)).FnCol) {
|
|
return uint8(SQLITE_AFF_INTEGER)
|
|
}
|
|
return (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(iCol)*16))).Faffinity
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add a new name/number pair to a VList. This might require that the
|
|
// ** VList object be reallocated, so return the new VList. If an OOM
|
|
// ** error occurs, the original VList returned and the
|
|
// ** db->mallocFailed flag is set.
|
|
// **
|
|
// ** A VList is really just an array of integers. To destroy a VList,
|
|
// ** simply pass it to sqlite3DbFree().
|
|
// **
|
|
// ** The first integer is the number of integers allocated for the whole
|
|
// ** VList. The second integer is the number of integers actually used.
|
|
// ** Each name/number pair is encoded by subsequent groups of 3 or more
|
|
// ** integers.
|
|
// **
|
|
// ** Each name/number pair starts with two integers which are the numeric
|
|
// ** value for the pair and the size of the name/number pair, respectively.
|
|
// ** The text name overlays one or more following integers. The text name
|
|
// ** is always zero-terminated.
|
|
// **
|
|
// ** Conceptually:
|
|
// **
|
|
// ** struct VList {
|
|
// ** int nAlloc; // Number of allocated slots
|
|
// ** int nUsed; // Number of used slots
|
|
// ** struct VListEntry {
|
|
// ** int iValue; // Value for this entry
|
|
// ** int nSlot; // Slots used by this entry
|
|
// ** // ... variable name goes here
|
|
// ** } a[0];
|
|
// ** }
|
|
// **
|
|
// ** During code generation, pointers to the variable names within the
|
|
// ** VList are taken. When that happens, nAlloc is set to zero as an
|
|
// ** indication that the VList may never again be enlarged, since the
|
|
// ** accompanying realloc() would invalidate the pointers.
|
|
// */
|
|
func _sqlite3VListAdd(tls *libc.TLS, db uintptr, pIn uintptr, zName uintptr, nName int32, iVal int32) (r uintptr) {
|
|
var i, nInt int32
|
|
var nAlloc Tsqlite3_int64
|
|
var pOut, z uintptr
|
|
var v1 int64
|
|
_, _, _, _, _, _ = i, nAlloc, nInt, pOut, z, v1 /* Index in pIn[] where zName is stored */
|
|
nInt = nName/int32(4) + int32(3)
|
|
/* Verify ok to add new elements */
|
|
if pIn == uintptr(0) || **(**TVList)(__ccgo_up(pIn + 1*4))+nInt > **(**TVList)(__ccgo_up(pIn)) {
|
|
if pIn != 0 {
|
|
v1 = int64(2) * int64(**(**TVList)(__ccgo_up(pIn)))
|
|
} else {
|
|
v1 = int64(10)
|
|
}
|
|
/* Enlarge the allocation */
|
|
nAlloc = v1 + int64(nInt)
|
|
pOut = _sqlite3DbRealloc(tls, db, pIn, libc.Uint64FromInt64(nAlloc)*uint64(4))
|
|
if pOut == uintptr(0) {
|
|
return pIn
|
|
}
|
|
if pIn == uintptr(0) {
|
|
**(**TVList)(__ccgo_up(pOut + 1*4)) = int32(2)
|
|
}
|
|
pIn = pOut
|
|
**(**TVList)(__ccgo_up(pIn)) = int32(nAlloc)
|
|
}
|
|
i = **(**TVList)(__ccgo_up(pIn + 1*4))
|
|
**(**TVList)(__ccgo_up(pIn + uintptr(i)*4)) = iVal
|
|
**(**TVList)(__ccgo_up(pIn + uintptr(i+int32(1))*4)) = nInt
|
|
z = pIn + uintptr(i+int32(2))*4
|
|
**(**TVList)(__ccgo_up(pIn + 1*4)) = i + nInt
|
|
libc.Xmemcpy(tls, z, zName, libc.Uint64FromInt32(nName))
|
|
**(**uint8)(__ccgo_up(z + uintptr(nName))) = uint8(0)
|
|
return pIn
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the number of the variable named zName, if it is in VList.
|
|
// ** or return 0 if there is no such variable.
|
|
// */
|
|
func _sqlite3VListNameToNum(tls *libc.TLS, pIn uintptr, zName uintptr, nName int32) (r int32) {
|
|
var i, mx int32
|
|
var z uintptr
|
|
_, _, _ = i, mx, z
|
|
if pIn == uintptr(0) {
|
|
return 0
|
|
}
|
|
mx = **(**TVList)(__ccgo_up(pIn + 1*4))
|
|
i = int32(2)
|
|
for cond := true; cond; cond = i < mx {
|
|
z = pIn + uintptr(i+int32(2))*4
|
|
if libc.Xstrncmp(tls, z, zName, libc.Uint64FromInt32(nName)) == 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(nName)))) == 0 {
|
|
return **(**TVList)(__ccgo_up(pIn + uintptr(i)*4))
|
|
}
|
|
i = i + **(**TVList)(__ccgo_up(pIn + uintptr(i+int32(1))*4))
|
|
}
|
|
return 0
|
|
}
|
|
|
|
/************** End of util.c ************************************************/
|
|
/************** Begin file hash.c ********************************************/
|
|
/*
|
|
** 2001 September 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 is the implementation of generic hash-tables
|
|
** used in SQLite.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
/* #include <assert.h> */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Print into memory obtained from sqliteMalloc(). Use the internal
|
|
// ** %-conversion extensions.
|
|
// */
|
|
func _sqlite3VMPrintf(tls *libc.TLS, db uintptr, zFormat uintptr, ap Tva_list) (r uintptr) {
|
|
bp := tls.Alloc(112)
|
|
defer tls.Free(112)
|
|
var z uintptr
|
|
var _ /* acc at bp+72 */ TStrAccum
|
|
var _ /* zBase at bp+0 */ [70]uint8
|
|
_ = z
|
|
_sqlite3StrAccumInit(tls, bp+72, db, bp, int32(70), **(**int32)(__ccgo_up(db + 136)))
|
|
(**(**TStrAccum)(__ccgo_up(bp + 72))).FprintfFlags = uint8(SQLITE_PRINTF_INTERNAL)
|
|
Xsqlite3_str_vappendf(tls, bp+72, zFormat, ap)
|
|
z = _sqlite3StrAccumFinish(tls, bp+72)
|
|
if libc.Int32FromUint8((**(**TStrAccum)(__ccgo_up(bp + 72))).FaccError) == int32(SQLITE_NOMEM) {
|
|
_sqlite3OomFault(tls, db)
|
|
}
|
|
return z
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine checks for a byte-order mark at the beginning of the
|
|
// ** UTF-16 string stored in *pMem. If one is present, it is removed and
|
|
// ** the encoding of the Mem adjusted. This routine does not do any
|
|
// ** byte-swapping, it just sets Mem.enc appropriately.
|
|
// **
|
|
// ** The allocation (static, dynamic etc.) and encoding of the Mem may be
|
|
// ** changed by this function.
|
|
// */
|
|
func _sqlite3VdbeMemHandleBom(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
var b1, b2, bom Tu8
|
|
var rc int32
|
|
var v1 uintptr
|
|
_, _, _, _, _ = b1, b2, bom, rc, v1
|
|
rc = SQLITE_OK
|
|
bom = uint8(0)
|
|
if (*TMem)(unsafe.Pointer(pMem)).Fn > int32(1) {
|
|
b1 = **(**Tu8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz))
|
|
b2 = **(**Tu8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + libc.UintptrFromInt32(1)))
|
|
if libc.Int32FromUint8(b1) == int32(0xFE) && libc.Int32FromUint8(b2) == int32(0xFF) {
|
|
bom = uint8(SQLITE_UTF16BE)
|
|
}
|
|
if libc.Int32FromUint8(b1) == int32(0xFF) && libc.Int32FromUint8(b2) == int32(0xFE) {
|
|
bom = uint8(SQLITE_UTF16LE)
|
|
}
|
|
}
|
|
if bom != 0 {
|
|
rc = _sqlite3VdbeMemMakeWriteable(tls, pMem)
|
|
if rc == SQLITE_OK {
|
|
**(**int32)(__ccgo_up(pMem + 16)) -= int32(2)
|
|
libc.Xmemmove(tls, (*TMem)(unsafe.Pointer(pMem)).Fz, (*TMem)(unsafe.Pointer(pMem)).Fz+2, libc.Uint64FromInt32((*TMem)(unsafe.Pointer(pMem)).Fn))
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn))) = uint8('\000')
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn+int32(1)))) = uint8('\000')
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = bom
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change the value of a Mem to be a string or a BLOB.
|
|
// **
|
|
// ** The memory management strategy depends on the value of the xDel
|
|
// ** parameter. If the value passed is SQLITE_TRANSIENT, then the
|
|
// ** string is copied into a (possibly existing) buffer managed by the
|
|
// ** Mem structure. Otherwise, any existing buffer is freed and the
|
|
// ** pointer copied.
|
|
// **
|
|
// ** If the string is too large (if it exceeds the SQLITE_LIMIT_LENGTH
|
|
// ** size limit) then no memory allocation occurs. If the string can be
|
|
// ** stored without allocating memory, then it is. If a memory allocation
|
|
// ** is required to store the string, then value of pMem is unchanged. In
|
|
// ** either case, SQLITE_TOOBIG is returned.
|
|
// **
|
|
// ** The "enc" parameter is the text encoding for the string, or zero
|
|
// ** to store a blob.
|
|
// **
|
|
// ** If n is negative, then the string consists of all bytes up to but
|
|
// ** excluding the first zero character. The n parameter must be
|
|
// ** non-negative for blobs.
|
|
// */
|
|
func _sqlite3VdbeMemSetStr(tls *libc.TLS, pMem uintptr, z uintptr, n Ti64, enc Tu8, __ccgo_fp_xDel uintptr) (r int32) {
|
|
var flags Tu16
|
|
var iLimit, v2 int32
|
|
var nAlloc, nByte Ti64
|
|
var v3 int64
|
|
_, _, _, _, _, _ = flags, iLimit, nAlloc, nByte, v2, v3
|
|
nByte = n /* New value for pMem->flags */
|
|
/* If z is a NULL pointer, set pMem to contain an SQL NULL. */
|
|
if !(z != 0) {
|
|
_sqlite3VdbeMemSetNull(tls, pMem)
|
|
return SQLITE_OK
|
|
}
|
|
if (*TMem)(unsafe.Pointer(pMem)).Fdb != 0 {
|
|
iLimit = **(**int32)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fdb + 136))
|
|
} else {
|
|
iLimit = int32(SQLITE_MAX_LENGTH)
|
|
}
|
|
if nByte < 0 {
|
|
if libc.Int32FromUint8(enc) == int32(SQLITE_UTF8) {
|
|
nByte = libc.Int64FromUint64(libc.Xstrlen(tls, z))
|
|
} else {
|
|
nByte = 0
|
|
for {
|
|
if !(nByte <= int64(iLimit) && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(nByte))))|libc.Int32FromUint8(**(**uint8)(__ccgo_up(z + uintptr(nByte+int64(1))))) != 0) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
nByte = nByte + int64(2)
|
|
}
|
|
}
|
|
flags = libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Str) | libc.Int32FromInt32(MEM_Term))
|
|
} else {
|
|
if libc.Int32FromUint8(enc) == 0 {
|
|
flags = uint16(MEM_Blob)
|
|
enc = uint8(SQLITE_UTF8)
|
|
} else {
|
|
flags = uint16(MEM_Str)
|
|
}
|
|
}
|
|
if nByte > int64(iLimit) {
|
|
if __ccgo_fp_xDel != 0 && __ccgo_fp_xDel != uintptr(-libc.Int32FromInt32(1)) {
|
|
if __ccgo_fp_xDel == __ccgo_fp(_sqlite3RowSetClear) {
|
|
_sqlite3DbFree(tls, (*TMem)(unsafe.Pointer(pMem)).Fdb, z)
|
|
} else {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xDel})))(tls, z)
|
|
}
|
|
}
|
|
_sqlite3VdbeMemSetNull(tls, pMem)
|
|
return _sqlite3ErrorToParser(tls, (*TMem)(unsafe.Pointer(pMem)).Fdb, int32(SQLITE_TOOBIG))
|
|
}
|
|
/* The following block sets the new values of Mem.z and Mem.xDel. It
|
|
** also sets a flag in local variable "flags" to indicate the memory
|
|
** management (one of MEM_Dyn or MEM_Static).
|
|
*/
|
|
if __ccgo_fp_xDel == uintptr(-libc.Int32FromInt32(1)) {
|
|
nAlloc = nByte
|
|
if libc.Int32FromUint16(flags)&int32(MEM_Term) != 0 {
|
|
if libc.Int32FromUint8(enc) == int32(SQLITE_UTF8) {
|
|
v2 = int32(1)
|
|
} else {
|
|
v2 = int32(2)
|
|
}
|
|
nAlloc = nAlloc + int64(v2)
|
|
}
|
|
if nAlloc > int64(libc.Int32FromInt32(32)) {
|
|
v3 = nAlloc
|
|
} else {
|
|
v3 = int64(libc.Int32FromInt32(32))
|
|
}
|
|
if _sqlite3VdbeMemClearAndResize(tls, pMem, int32(v3)) != 0 {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
libc.Xmemcpy(tls, (*TMem)(unsafe.Pointer(pMem)).Fz, z, libc.Uint64FromInt64(nAlloc))
|
|
} else {
|
|
_sqlite3VdbeMemRelease(tls, pMem)
|
|
(*TMem)(unsafe.Pointer(pMem)).Fz = z
|
|
if __ccgo_fp_xDel == __ccgo_fp(_sqlite3RowSetClear) {
|
|
(*TMem)(unsafe.Pointer(pMem)).FzMalloc = (*TMem)(unsafe.Pointer(pMem)).Fz
|
|
(*TMem)(unsafe.Pointer(pMem)).FszMalloc = _sqlite3DbMallocSize(tls, (*TMem)(unsafe.Pointer(pMem)).Fdb, (*TMem)(unsafe.Pointer(pMem)).FzMalloc)
|
|
} else {
|
|
(*TMem)(unsafe.Pointer(pMem)).FxDel = __ccgo_fp_xDel
|
|
if __ccgo_fp_xDel == libc.UintptrFromInt32(0) {
|
|
v2 = int32(MEM_Static)
|
|
} else {
|
|
v2 = int32(MEM_Dyn)
|
|
}
|
|
flags = libc.Uint16FromInt32(int32(flags) | v2)
|
|
}
|
|
}
|
|
(*TMem)(unsafe.Pointer(pMem)).Fn = int32(nByte & libc.Int64FromInt32(0x7fffffff))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = flags
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = enc
|
|
if libc.Int32FromUint8(enc) > int32(SQLITE_UTF8) && _sqlite3VdbeMemHandleBom(tls, pMem) != 0 {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Like sqlite3VdbeMemSetStr() except:
|
|
// **
|
|
// ** enc is always SQLITE_UTF8
|
|
// ** pMem->db is always non-NULL
|
|
// */
|
|
func _sqlite3VdbeMemSetText(tls *libc.TLS, pMem uintptr, z uintptr, n Ti64, __ccgo_fp_xDel uintptr) (r int32) {
|
|
var flags Tu16
|
|
var nAlloc, nByte Ti64
|
|
var v1 int64
|
|
_, _, _, _ = flags, nAlloc, nByte, v1
|
|
nByte = n
|
|
/* If z is a NULL pointer, set pMem to contain an SQL NULL. */
|
|
if !(z != 0) {
|
|
_sqlite3VdbeMemSetNull(tls, pMem)
|
|
return SQLITE_OK
|
|
}
|
|
if nByte < 0 {
|
|
nByte = libc.Int64FromUint64(libc.Xstrlen(tls, z))
|
|
flags = libc.Uint16FromInt32(libc.Int32FromInt32(MEM_Str) | libc.Int32FromInt32(MEM_Term))
|
|
} else {
|
|
flags = uint16(MEM_Str)
|
|
}
|
|
if nByte > int64(**(**int32)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fdb + 136))) {
|
|
if __ccgo_fp_xDel != 0 && __ccgo_fp_xDel != uintptr(-libc.Int32FromInt32(1)) {
|
|
if __ccgo_fp_xDel == __ccgo_fp(_sqlite3RowSetClear) {
|
|
_sqlite3DbFree(tls, (*TMem)(unsafe.Pointer(pMem)).Fdb, z)
|
|
} else {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xDel})))(tls, z)
|
|
}
|
|
}
|
|
_sqlite3VdbeMemSetNull(tls, pMem)
|
|
return _sqlite3ErrorToParser(tls, (*TMem)(unsafe.Pointer(pMem)).Fdb, int32(SQLITE_TOOBIG))
|
|
}
|
|
/* The following block sets the new values of Mem.z and Mem.xDel. It
|
|
** also sets a flag in local variable "flags" to indicate the memory
|
|
** management (one of MEM_Dyn or MEM_Static).
|
|
*/
|
|
if __ccgo_fp_xDel == uintptr(-libc.Int32FromInt32(1)) {
|
|
nAlloc = nByte + int64(1)
|
|
if nAlloc > int64(libc.Int32FromInt32(32)) {
|
|
v1 = nAlloc
|
|
} else {
|
|
v1 = int64(libc.Int32FromInt32(32))
|
|
}
|
|
if _sqlite3VdbeMemClearAndResize(tls, pMem, int32(v1)) != 0 {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
libc.Xmemcpy(tls, (*TMem)(unsafe.Pointer(pMem)).Fz, z, libc.Uint64FromInt64(nByte))
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr(nByte))) = uint8(0)
|
|
} else {
|
|
_sqlite3VdbeMemRelease(tls, pMem)
|
|
(*TMem)(unsafe.Pointer(pMem)).Fz = z
|
|
if __ccgo_fp_xDel == __ccgo_fp(_sqlite3RowSetClear) {
|
|
(*TMem)(unsafe.Pointer(pMem)).FzMalloc = (*TMem)(unsafe.Pointer(pMem)).Fz
|
|
(*TMem)(unsafe.Pointer(pMem)).FszMalloc = _sqlite3DbMallocSize(tls, (*TMem)(unsafe.Pointer(pMem)).Fdb, (*TMem)(unsafe.Pointer(pMem)).FzMalloc)
|
|
(*TMem)(unsafe.Pointer(pMem)).FxDel = uintptr(0)
|
|
} else {
|
|
if __ccgo_fp_xDel == libc.UintptrFromInt32(0) {
|
|
(*TMem)(unsafe.Pointer(pMem)).FxDel = __ccgo_fp_xDel
|
|
flags = libc.Uint16FromInt32(int32(flags) | libc.Int32FromInt32(MEM_Static))
|
|
} else {
|
|
(*TMem)(unsafe.Pointer(pMem)).FxDel = __ccgo_fp_xDel
|
|
flags = libc.Uint16FromInt32(int32(flags) | libc.Int32FromInt32(MEM_Dyn))
|
|
}
|
|
}
|
|
}
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = flags
|
|
(*TMem)(unsafe.Pointer(pMem)).Fn = int32(nByte & libc.Int64FromInt32(0x7fffffff))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = uint8(SQLITE_UTF8)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If pMem is already a string, detect if it is a zero-terminated
|
|
// ** string, or make it into one if possible, and mark it as such.
|
|
// **
|
|
// ** This is an optimization. Correct operation continues even if
|
|
// ** this routine is a no-op.
|
|
// **
|
|
// ** Return true if the strig is zero-terminated after this routine is
|
|
// ** called and false if it is not.
|
|
// */
|
|
func _sqlite3VdbeMemZeroTerminateIfAble(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Term)|libc.Int32FromInt32(MEM_Ephem)|libc.Int32FromInt32(MEM_Static)) != int32(MEM_Str) {
|
|
/* pMem must be a string, and it cannot be an ephemeral or static string */
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8((*TMem)(unsafe.Pointer(pMem)).Fenc) != int32(SQLITE_UTF8) {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Dyn) != 0 {
|
|
if (*TMem)(unsafe.Pointer(pMem)).FxDel == __ccgo_fp(Xsqlite3_free) && Xsqlite3_msize(tls, (*TMem)(unsafe.Pointer(pMem)).Fz) >= libc.Uint64FromInt32((*TMem)(unsafe.Pointer(pMem)).Fn+libc.Int32FromInt32(1)) {
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn))) = uint8(0)
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
return int32(1)
|
|
}
|
|
if (*TMem)(unsafe.Pointer(pMem)).FxDel == __ccgo_fp(_sqlite3RCStrUnref) {
|
|
/* Blindly assume that all RCStr objects are zero-terminated */
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
return int32(1)
|
|
}
|
|
} else {
|
|
if (*TMem)(unsafe.Pointer(pMem)).FszMalloc >= (*TMem)(unsafe.Pointer(pMem)).Fn+int32(1) {
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn))) = uint8(0)
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
return int32(1)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is called by code in select.c before it calls sqlite3WhereBegin()
|
|
// ** to begin iterating through the sub-query results. It is used to allocate
|
|
// ** and initialize registers and cursors used by sqlite3WindowCodeStep().
|
|
// */
|
|
func _sqlite3WindowCodeInit(tls *libc.TLS, pParse uintptr, pSelect uintptr) {
|
|
var nEphExpr, nExpr, v1 int32
|
|
var p, pKeyInfo, pList, pMWin, pWin, v, v2 uintptr
|
|
_, _, _, _, _, _, _, _, _, _ = nEphExpr, nExpr, p, pKeyInfo, pList, pMWin, pWin, v, v1, v2
|
|
nEphExpr = (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer((*TSubquery)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpSrc + 8 + 72)))).FpSelect)).FpEList)).FnExpr
|
|
pMWin = (*TSelect)(unsafe.Pointer(pSelect)).FpWin
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenEphemeral), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr, nEphExpr)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenDup), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr+int32(1), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenDup), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr+int32(2), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenDup), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr+int32(3), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr)
|
|
/* Allocate registers to use for PARTITION BY values, if any. Initialize
|
|
** said registers to NULL. */
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FpPartition != 0 {
|
|
nExpr = (*TExprList)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pMWin)).FpPartition)).FnExpr
|
|
(*TWindow)(unsafe.Pointer(pMWin)).FregPart = (*TParse)(unsafe.Pointer(pParse)).FnMem + int32(1)
|
|
**(**int32)(__ccgo_up(pParse + 60)) += nExpr
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Null), 0, (*TWindow)(unsafe.Pointer(pMWin)).FregPart, (*TWindow)(unsafe.Pointer(pMWin)).FregPart+nExpr-int32(1))
|
|
}
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
(*TWindow)(unsafe.Pointer(pMWin)).FregOne = v1
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Integer), int32(1), (*TWindow)(unsafe.Pointer(pMWin)).FregOne)
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FeExclude != 0 {
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
(*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid = v1
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
(*TWindow)(unsafe.Pointer(pMWin)).FregEndRowid = v1
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
(*TWindow)(unsafe.Pointer(pMWin)).FcsrApp = v1
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Integer), int32(1), (*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Integer), 0, (*TWindow)(unsafe.Pointer(pMWin)).FregEndRowid)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenDup), (*TWindow)(unsafe.Pointer(pMWin)).FcsrApp, (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr)
|
|
return
|
|
}
|
|
pWin = pMWin
|
|
for {
|
|
if !(pWin != 0) {
|
|
break
|
|
}
|
|
p = (*TWindow)(unsafe.Pointer(pWin)).FpWFunc
|
|
if (*TFuncDef)(unsafe.Pointer(p)).FfuncFlags&uint32(SQLITE_FUNC_MINMAX) != 0 && libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pWin)).FeStart) != int32(TK_UNBOUNDED) {
|
|
pList = *(*uintptr)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pWin)).FpOwner + 32))
|
|
pKeyInfo = _sqlite3KeyInfoFromExprList(tls, pParse, pList, 0, 0)
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
(*TWindow)(unsafe.Pointer(pWin)).FcsrApp = v1
|
|
(*TWindow)(unsafe.Pointer(pWin)).FregApp = (*TParse)(unsafe.Pointer(pParse)).FnMem + int32(1)
|
|
**(**int32)(__ccgo_up(pParse + 60)) += int32(3)
|
|
if pKeyInfo != 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up((*TFuncDef)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pWin)).FpWFunc)).FzName + 1))) == int32('i') {
|
|
**(**Tu8)(__ccgo_up((*TKeyInfo)(unsafe.Pointer(pKeyInfo)).FaSortFlags)) = uint8(KEYINFO_ORDER_DESC)
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenEphemeral), (*TWindow)(unsafe.Pointer(pWin)).FcsrApp, int32(2))
|
|
_sqlite3VdbeAppendP4(tls, v, pKeyInfo, -int32(9))
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Integer), 0, (*TWindow)(unsafe.Pointer(pWin)).FregApp+int32(1))
|
|
} else {
|
|
if (*TFuncDef)(unsafe.Pointer(p)).FzName == uintptr(unsafe.Pointer(&_nth_valueName)) || (*TFuncDef)(unsafe.Pointer(p)).FzName == uintptr(unsafe.Pointer(&_first_valueName)) {
|
|
/* Allocate two registers at pWin->regApp. These will be used to
|
|
** store the start and end index of the current frame. */
|
|
(*TWindow)(unsafe.Pointer(pWin)).FregApp = (*TParse)(unsafe.Pointer(pParse)).FnMem + int32(1)
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
(*TWindow)(unsafe.Pointer(pWin)).FcsrApp = v1
|
|
**(**int32)(__ccgo_up(pParse + 60)) += int32(2)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenDup), (*TWindow)(unsafe.Pointer(pWin)).FcsrApp, (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr)
|
|
} else {
|
|
if (*TFuncDef)(unsafe.Pointer(p)).FzName == uintptr(unsafe.Pointer(&_leadName)) || (*TFuncDef)(unsafe.Pointer(p)).FzName == uintptr(unsafe.Pointer(&_lagName)) {
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
(*TWindow)(unsafe.Pointer(pWin)).FcsrApp = v1
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenDup), (*TWindow)(unsafe.Pointer(pWin)).FcsrApp, (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr)
|
|
}
|
|
}
|
|
}
|
|
goto _9
|
|
_9:
|
|
;
|
|
pWin = (*TWindow)(unsafe.Pointer(pWin)).FpNextWin
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the SELECT statement passed as the second argument does not invoke
|
|
// ** any SQL window functions, this function is a no-op. Otherwise, it
|
|
// ** rewrites the SELECT statement so that window function xStep functions
|
|
// ** are invoked in the correct order as described under "SELECT REWRITING"
|
|
// ** at the top of this file.
|
|
// */
|
|
func _sqlite3WindowRewrite(tls *libc.TLS, pParse uintptr, p uintptr) (r int32) {
|
|
bp := tls.Alloc(64)
|
|
defer tls.Free(64)
|
|
var db, pArgs, pFilter, pGroupBy, pHaving, pMWin, pSort, pSrc, pSub, pTab, pTab2, pWhere, pWin, v, v2 uintptr
|
|
var nSave, rc, v1 int32
|
|
var selFlags Tu32
|
|
var _ /* pSublist at bp+0 */ uintptr
|
|
var _ /* w at bp+8 */ TWalker
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = db, nSave, pArgs, pFilter, pGroupBy, pHaving, pMWin, pSort, pSrc, pSub, pTab, pTab2, pWhere, pWin, rc, selFlags, v, v1, v2
|
|
rc = SQLITE_OK
|
|
if (*TSelect)(unsafe.Pointer(p)).FpWin != 0 && (*TSelect)(unsafe.Pointer(p)).FpPrior == uintptr(0) && (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_WinRewrite) == uint32(0) && !(libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= libc.Int32FromInt32(PARSE_MODE_RENAME)) {
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pSub = uintptr(0) /* The subquery */
|
|
pSrc = (*TSelect)(unsafe.Pointer(p)).FpSrc
|
|
pWhere = (*TSelect)(unsafe.Pointer(p)).FpWhere
|
|
pGroupBy = (*TSelect)(unsafe.Pointer(p)).FpGroupBy
|
|
pHaving = (*TSelect)(unsafe.Pointer(p)).FpHaving
|
|
pSort = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* Expression list for sub-query */
|
|
pMWin = (*TSelect)(unsafe.Pointer(p)).FpWin
|
|
selFlags = (*TSelect)(unsafe.Pointer(p)).FselFlags
|
|
pTab = _sqlite3DbMallocZero(tls, db, uint64(120))
|
|
if pTab == uintptr(0) {
|
|
return _sqlite3ErrorToParser(tls, db, int32(SQLITE_NOMEM))
|
|
}
|
|
_sqlite3AggInfoPersistWalkerInit(tls, bp+8, pParse)
|
|
_sqlite3WalkSelect(tls, bp+8, p)
|
|
if (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_Aggregate) == uint32(0) {
|
|
(**(**TWalker)(__ccgo_up(bp + 8))).FxExprCallback = __ccgo_fp(_disallowAggregatesInOrderByCb)
|
|
(**(**TWalker)(__ccgo_up(bp + 8))).FxSelectCallback = uintptr(0)
|
|
_sqlite3WalkExprList(tls, bp+8, (*TSelect)(unsafe.Pointer(p)).FpOrderBy)
|
|
}
|
|
(*TSelect)(unsafe.Pointer(p)).FpSrc = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(p)).FpWhere = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(p)).FpGroupBy = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(p)).FpHaving = uintptr(0)
|
|
**(**Tu32)(__ccgo_up(p + 4)) &= ^libc.Uint32FromInt32(SF_Aggregate)
|
|
**(**Tu32)(__ccgo_up(p + 4)) |= uint32(SF_WinRewrite)
|
|
/* Create the ORDER BY clause for the sub-select. This is the concatenation
|
|
** of the window PARTITION and ORDER BY clauses. Then, if this makes it
|
|
** redundant, remove the ORDER BY from the parent SELECT. */
|
|
pSort = _exprListAppendList(tls, pParse, uintptr(0), (*TWindow)(unsafe.Pointer(pMWin)).FpPartition, int32(1))
|
|
pSort = _exprListAppendList(tls, pParse, pSort, (*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy, int32(1))
|
|
if pSort != 0 && (*TSelect)(unsafe.Pointer(p)).FpOrderBy != 0 && (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpOrderBy)).FnExpr <= (*TExprList)(unsafe.Pointer(pSort)).FnExpr {
|
|
nSave = (*TExprList)(unsafe.Pointer(pSort)).FnExpr
|
|
(*TExprList)(unsafe.Pointer(pSort)).FnExpr = (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpOrderBy)).FnExpr
|
|
if _sqlite3ExprListCompare(tls, pSort, (*TSelect)(unsafe.Pointer(p)).FpOrderBy, -int32(1)) == 0 {
|
|
_sqlite3ExprListDelete(tls, db, (*TSelect)(unsafe.Pointer(p)).FpOrderBy)
|
|
(*TSelect)(unsafe.Pointer(p)).FpOrderBy = uintptr(0)
|
|
}
|
|
(*TExprList)(unsafe.Pointer(pSort)).FnExpr = nSave
|
|
}
|
|
/* Assign a cursor number for the ephemeral table used to buffer rows.
|
|
** The OpenEphemeral instruction is coded later, after it is known how
|
|
** many columns the table will have. */
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
(*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr = v1
|
|
**(**int32)(__ccgo_up(pParse + 56)) += int32(3)
|
|
_selectWindowRewriteEList(tls, pParse, pMWin, pSrc, (*TSelect)(unsafe.Pointer(p)).FpEList, pTab, bp)
|
|
_selectWindowRewriteEList(tls, pParse, pMWin, pSrc, (*TSelect)(unsafe.Pointer(p)).FpOrderBy, pTab, bp)
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
v1 = (*TExprList)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*TWindow)(unsafe.Pointer(pMWin)).FnBufferCol = v1
|
|
/* Append the PARTITION BY and ORDER BY expressions to the to the
|
|
** sub-select expression list. They are required to figure out where
|
|
** boundaries for partitions and sets of peer rows lie. */
|
|
**(**uintptr)(__ccgo_up(bp)) = _exprListAppendList(tls, pParse, **(**uintptr)(__ccgo_up(bp)), (*TWindow)(unsafe.Pointer(pMWin)).FpPartition, 0)
|
|
**(**uintptr)(__ccgo_up(bp)) = _exprListAppendList(tls, pParse, **(**uintptr)(__ccgo_up(bp)), (*TWindow)(unsafe.Pointer(pMWin)).FpOrderBy, 0)
|
|
/* Append the arguments passed to each window function to the
|
|
** sub-select expression list. Also allocate two registers for each
|
|
** window function - one for the accumulator, another for interim
|
|
** results. */
|
|
pWin = pMWin
|
|
for {
|
|
if !(pWin != 0) {
|
|
break
|
|
}
|
|
pArgs = *(*uintptr)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pWin)).FpOwner + 32))
|
|
if (*TFuncDef)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pWin)).FpWFunc)).FfuncFlags&uint32(SQLITE_SUBTYPE) != 0 {
|
|
_selectWindowRewriteEList(tls, pParse, pMWin, pSrc, pArgs, pTab, bp)
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
v1 = (*TExprList)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*TWindow)(unsafe.Pointer(pWin)).FiArgCol = v1
|
|
(*TWindow)(unsafe.Pointer(pWin)).FbExprArgs = uint8(1)
|
|
} else {
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
v1 = (*TExprList)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*TWindow)(unsafe.Pointer(pWin)).FiArgCol = v1
|
|
**(**uintptr)(__ccgo_up(bp)) = _exprListAppendList(tls, pParse, **(**uintptr)(__ccgo_up(bp)), pArgs, 0)
|
|
}
|
|
if (*TWindow)(unsafe.Pointer(pWin)).FpFilter != 0 {
|
|
pFilter = _sqlite3ExprDup(tls, db, (*TWindow)(unsafe.Pointer(pWin)).FpFilter, 0)
|
|
**(**uintptr)(__ccgo_up(bp)) = _sqlite3ExprListAppend(tls, pParse, **(**uintptr)(__ccgo_up(bp)), pFilter)
|
|
}
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
(*TWindow)(unsafe.Pointer(pWin)).FregAccum = v1
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
(*TWindow)(unsafe.Pointer(pWin)).FregResult = v1
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Null), 0, (*TWindow)(unsafe.Pointer(pWin)).FregAccum)
|
|
goto _4
|
|
_4:
|
|
;
|
|
pWin = (*TWindow)(unsafe.Pointer(pWin)).FpNextWin
|
|
}
|
|
/* If there is no ORDER BY or PARTITION BY clause, and the window
|
|
** function accepts zero arguments, and there are no other columns
|
|
** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible
|
|
** that pSublist is still NULL here. Add a constant expression here to
|
|
** keep everything legal in this case.
|
|
*/
|
|
if **(**uintptr)(__ccgo_up(bp)) == uintptr(0) {
|
|
**(**uintptr)(__ccgo_up(bp)) = _sqlite3ExprListAppend(tls, pParse, uintptr(0), _sqlite3ExprInt32(tls, db, 0))
|
|
}
|
|
pSub = _sqlite3SelectNew(tls, pParse, **(**uintptr)(__ccgo_up(bp)), pSrc, pWhere, pGroupBy, pHaving, pSort, uint32(0), uintptr(0))
|
|
(*TSelect)(unsafe.Pointer(p)).FpSrc = _sqlite3SrcListAppend(tls, pParse, uintptr(0), uintptr(0), uintptr(0))
|
|
/* Due to db->mallocFailed test inside
|
|
** of sqlite3DbMallocRawNN() called from
|
|
** sqlite3SrcListAppend() */
|
|
if (*TSelect)(unsafe.Pointer(p)).FpSrc == uintptr(0) {
|
|
_sqlite3SelectDelete(tls, db, pSub)
|
|
} else {
|
|
if _sqlite3SrcItemAttachSubquery(tls, pParse, (*TSelect)(unsafe.Pointer(p)).FpSrc+8, pSub, 0) != 0 {
|
|
libc.SetBitFieldPtr32Uint32((*TSelect)(unsafe.Pointer(p)).FpSrc+8+24+4, libc.Uint32FromInt32(1), 4, 0x10)
|
|
_sqlite3SrcListAssignCursors(tls, pParse, (*TSelect)(unsafe.Pointer(p)).FpSrc)
|
|
**(**Tu32)(__ccgo_up(pSub + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(SF_Expanded) | libc.Int32FromInt32(SF_OrderByReqd))
|
|
pTab2 = _sqlite3ResultSetOfSelect(tls, pParse, pSub, uint8(SQLITE_AFF_NONE))
|
|
**(**Tu32)(__ccgo_up(pSub + 4)) |= selFlags & uint32(SF_Aggregate)
|
|
if pTab2 == uintptr(0) {
|
|
/* Might actually be some other kind of error, but in that case
|
|
** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get
|
|
** the correct error message regardless. */
|
|
rc = int32(SQLITE_NOMEM)
|
|
} else {
|
|
libc.Xmemcpy(tls, pTab, pTab2, uint64(120))
|
|
**(**Tu32)(__ccgo_up(pTab + 48)) |= uint32(TF_Ephemeral)
|
|
(*(*TSrcItem)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpSrc + 8))).FpSTab = pTab
|
|
pTab = pTab2
|
|
libc.Xmemset(tls, bp+8, 0, uint64(48))
|
|
(**(**TWalker)(__ccgo_up(bp + 8))).FxExprCallback = __ccgo_fp(_sqlite3WindowExtraAggFuncDepth)
|
|
(**(**TWalker)(__ccgo_up(bp + 8))).FxSelectCallback = __ccgo_fp(_sqlite3WalkerDepthIncrease)
|
|
(**(**TWalker)(__ccgo_up(bp + 8))).FxSelectCallback2 = __ccgo_fp(_sqlite3WalkerDepthDecrease)
|
|
_sqlite3WalkSelect(tls, bp+8, pSub)
|
|
}
|
|
}
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
/* Defer deleting the temporary table pTab because if an error occurred,
|
|
** there could still be references to that table embedded in the
|
|
** result-set or ORDER BY clause of the SELECT statement p. */
|
|
_sqlite3ParserAddCleanup(tls, pParse, __ccgo_fp(_sqlite3DbFree), pTab)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return TRUE if the WHERE clause term pTerm is of a form where it
|
|
// ** could be used with an index to access pSrc, assuming an appropriate
|
|
// ** index existed.
|
|
// */
|
|
func _termCanDriveIndex(tls *libc.TLS, pTerm uintptr, pSrc uintptr, notReady TBitmask) (r int32) {
|
|
var aff uint8
|
|
var leftCol int32
|
|
_, _ = aff, leftCol
|
|
if (*TWhereTerm)(unsafe.Pointer(pTerm)).FleftCursor != (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_IS)) == 0 {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_LEFT)|libc.Int32FromInt32(JT_LTORJ)|libc.Int32FromInt32(JT_RIGHT)) != 0 && !(_constraintCompatibleWithOuterJoin(tls, pTerm, pSrc) != 0) {
|
|
return 0 /* See https://sqlite.org/forum/forumpost/51e6959f61 */
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqRight¬Ready != uint64(0) {
|
|
return 0
|
|
}
|
|
leftCol = (*(*struct {
|
|
FleftColumn int32
|
|
FiField int32
|
|
})(unsafe.Pointer(pTerm + 32))).FleftColumn
|
|
if leftCol < 0 {
|
|
return 0
|
|
}
|
|
aff = (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer((*TSrcItem)(unsafe.Pointer(pSrc)).FpSTab)).FaCol + uintptr(leftCol)*16))).Faffinity
|
|
if !(_sqlite3IndexAffinityOk(tls, (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr, aff) != 0) {
|
|
return 0
|
|
}
|
|
return _columnIsGoodIndexCandidate(tls, (*TSrcItem)(unsafe.Pointer(pSrc)).FpSTab, leftCol)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Construct a new Expr object from a single token */
|
|
func _tokenExpr(tls *libc.TLS, pParse uintptr, op int32, _t TToken) (r uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
*(*TToken)(unsafe.Pointer(bp)) = _t
|
|
var p, v1 uintptr
|
|
_, _ = p, v1
|
|
p = _sqlite3DbMallocRawNN(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(72)+uint64((**(**TToken)(__ccgo_up(bp))).Fn)+uint64(1))
|
|
if p != 0 {
|
|
/* memset(p, 0, sizeof(Expr)); */
|
|
(*TExpr)(unsafe.Pointer(p)).Fop = libc.Uint8FromInt32(op)
|
|
(*TExpr)(unsafe.Pointer(p)).FaffExpr = uint8(0)
|
|
(*TExpr)(unsafe.Pointer(p)).Fflags = uint32(EP_Leaf)
|
|
/* p->iAgg = -1; // Not required */
|
|
v1 = libc.UintptrFromInt32(0)
|
|
(*TExpr)(unsafe.Pointer(p)).FpRight = v1
|
|
(*TExpr)(unsafe.Pointer(p)).FpLeft = v1
|
|
(*TExpr)(unsafe.Pointer(p)).FpAggInfo = uintptr(0)
|
|
libc.Xmemset(tls, p+32, 0, uint64(8))
|
|
libc.Xmemset(tls, p+64, 0, uint64(8))
|
|
(*TExpr)(unsafe.Pointer(p)).Fop2 = uint8(0)
|
|
(*TExpr)(unsafe.Pointer(p)).FiTable = 0
|
|
(*TExpr)(unsafe.Pointer(p)).FiColumn = 0
|
|
*(*uintptr)(unsafe.Pointer(p + 8)) = p + 1*72
|
|
libc.Xmemcpy(tls, *(*uintptr)(unsafe.Pointer(p + 8)), (**(**TToken)(__ccgo_up(bp))).Fz, uint64((**(**TToken)(__ccgo_up(bp))).Fn))
|
|
**(**uint8)(__ccgo_up(*(*uintptr)(unsafe.Pointer(p + 8)) + uintptr((**(**TToken)(__ccgo_up(bp))).Fn))) = uint8(0)
|
|
*(*int32)(unsafe.Pointer(p + 52)) = int32(int64((**(**TToken)(__ccgo_up(bp))).Fz) - int64((*TParse)(unsafe.Pointer(pParse)).FzTail))
|
|
if libc.Int32FromUint8(_sqlite3CtypeMap[uint8(**(**uint8)(__ccgo_up(*(*uintptr)(unsafe.Pointer(p + 8)))))])&int32(0x80) != 0 {
|
|
_sqlite3DequoteExpr(tls, p)
|
|
}
|
|
(*TExpr)(unsafe.Pointer(p)).FnHeight = int32(1)
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
return _sqlite3RenameTokenMap(tls, pParse, p, bp)
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
func _unicodeSetCategories(tls *libc.TLS, p uintptr, zCat uintptr) (r int32) {
|
|
var z uintptr
|
|
_ = z
|
|
z = zCat
|
|
for **(**uint8)(__ccgo_up(z)) != 0 {
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32(' ') || libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) == int32('\t') {
|
|
z = z + 1
|
|
}
|
|
if **(**uint8)(__ccgo_up(z)) != 0 && _sqlite3Fts5UnicodeCatParse(tls, z, p+160) != 0 {
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) != int32(' ') && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) != int32('\t') && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) != int32('\000') {
|
|
z = z + 1
|
|
}
|
|
}
|
|
_sqlite3Fts5UnicodeAscii(tls, p+160, p)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** For OP_Column, factor out the case where content is loaded from
|
|
// ** overflow pages, so that the code to implement this case is separate
|
|
// ** the common case where all content fits on the page. Factoring out
|
|
// ** the code reduces register pressure and helps the common case
|
|
// ** to run faster.
|
|
// */
|
|
func _vdbeColumnFromOverflow(tls *libc.TLS, pC uintptr, iCol int32, t Tu32, iOffset Ti64, cacheStatus Tu32, colCacheCtr Tu32, pDest uintptr) (r int32) {
|
|
var db, pBuf, pCache, v1 uintptr
|
|
var encoding, len1, rc int32
|
|
_, _, _, _, _, _, _ = db, encoding, len1, pBuf, pCache, rc, v1
|
|
db = (*TMem)(unsafe.Pointer(pDest)).Fdb
|
|
encoding = libc.Int32FromUint8((*TMem)(unsafe.Pointer(pDest)).Fenc)
|
|
len1 = libc.Int32FromUint32(_sqlite3VdbeSerialTypeLen(tls, t))
|
|
if len1 > **(**int32)(__ccgo_up(db + 136)) {
|
|
return int32(SQLITE_TOOBIG)
|
|
}
|
|
if len1 > int32(4000) && (*TVdbeCursor)(unsafe.Pointer(pC)).FpKeyInfo == uintptr(0) {
|
|
if int32(TBool(*(*uint8)(unsafe.Pointer(pC + 8))&0x10>>4)) == 0 {
|
|
(*TVdbeCursor)(unsafe.Pointer(pC)).FpCache = _sqlite3DbMallocZero(tls, db, uint64(32))
|
|
if (*TVdbeCursor)(unsafe.Pointer(pC)).FpCache == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
libc.SetBitFieldPtr8Uint32(pC+8, libc.Uint32FromInt32(1), 4, 0x10)
|
|
}
|
|
pCache = (*TVdbeCursor)(unsafe.Pointer(pC)).FpCache
|
|
if (*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FpCValue == uintptr(0) || (*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FiCol != iCol || (*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FcacheStatus != cacheStatus || (*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FcolCacheCtr != colCacheCtr || (*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FiOffset != _sqlite3BtreeOffset(tls, *(*uintptr)(unsafe.Pointer(pC + 48))) {
|
|
if (*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FpCValue != 0 {
|
|
_sqlite3RCStrUnref(tls, (*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FpCValue)
|
|
}
|
|
v1 = _sqlite3RCStrNew(tls, libc.Uint64FromInt32(len1+int32(3)))
|
|
(*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FpCValue = v1
|
|
pBuf = v1
|
|
if pBuf == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
rc = _sqlite3BtreePayload(tls, *(*uintptr)(unsafe.Pointer(pC + 48)), libc.Uint32FromInt64(iOffset), libc.Uint32FromInt32(len1), pBuf)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
**(**uint8)(__ccgo_up(pBuf + uintptr(len1))) = uint8(0)
|
|
**(**uint8)(__ccgo_up(pBuf + uintptr(len1+int32(1)))) = uint8(0)
|
|
**(**uint8)(__ccgo_up(pBuf + uintptr(len1+int32(2)))) = uint8(0)
|
|
(*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FiCol = iCol
|
|
(*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FcacheStatus = cacheStatus
|
|
(*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FcolCacheCtr = colCacheCtr
|
|
(*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FiOffset = _sqlite3BtreeOffset(tls, *(*uintptr)(unsafe.Pointer(pC + 48)))
|
|
} else {
|
|
pBuf = (*TVdbeTxtBlbCache)(unsafe.Pointer(pCache)).FpCValue
|
|
}
|
|
_sqlite3RCStrRef(tls, pBuf)
|
|
if t&uint32(1) != 0 {
|
|
rc = _sqlite3VdbeMemSetStr(tls, pDest, pBuf, int64(len1), libc.Uint8FromInt32(encoding), __ccgo_fp(_sqlite3RCStrUnref))
|
|
v1 = pDest + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
} else {
|
|
rc = _sqlite3VdbeMemSetStr(tls, pDest, pBuf, int64(len1), uint8(0), __ccgo_fp(_sqlite3RCStrUnref))
|
|
}
|
|
} else {
|
|
rc = _sqlite3VdbeMemFromBtree(tls, *(*uintptr)(unsafe.Pointer(pC + 48)), libc.Uint32FromInt64(iOffset), libc.Uint32FromInt32(len1), pDest)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
_sqlite3VdbeSerialGet(tls, (*TMem)(unsafe.Pointer(pDest)).Fz, t, pDest)
|
|
if t&uint32(1) != uint32(0) && encoding == int32(SQLITE_UTF8) {
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pDest)).Fz + uintptr(len1))) = uint8(0)
|
|
v1 = pDest + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
}
|
|
}
|
|
v1 = pDest + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(MEM_Ephem))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** It is already known that pMem contains an unterminated string.
|
|
// ** Add the zero terminator.
|
|
// **
|
|
// ** Three bytes of zero are added. In this way, there is guaranteed
|
|
// ** to be a double-zero byte at an even byte boundary in order to
|
|
// ** terminate a UTF16 string, even if the initial size of the buffer
|
|
// ** is an odd number of bytes.
|
|
// */
|
|
func _vdbeMemAddTerminator(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if _sqlite3VdbeMemGrow(tls, pMem, (*TMem)(unsafe.Pointer(pMem)).Fn+int32(3), int32(1)) != 0 {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn))) = uint8(0)
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn+int32(1)))) = uint8(0)
|
|
**(**uint8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn+int32(2)))) = uint8(0)
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The index pIdx is used by a query and contains one or more expressions.
|
|
// ** In other words pIdx is an index on an expression. iIdxCur is the cursor
|
|
// ** number for the index and iDataCur is the cursor number for the corresponding
|
|
// ** table.
|
|
// **
|
|
// ** This routine adds IndexedExpr entries to the Parse->pIdxEpr field for
|
|
// ** each of the expressions in the index so that the expression code generator
|
|
// ** will know to replace occurrences of the indexed expression with
|
|
// ** references to the corresponding column of the index.
|
|
// */
|
|
func _whereAddIndexedExpr(tls *libc.TLS, pParse uintptr, pIdx uintptr, iIdxCur int32, pTabItem uintptr) {
|
|
var i, j int32
|
|
var p, pArg, pExpr, pTab uintptr
|
|
_, _, _, _, _, _ = i, j, p, pArg, pExpr, pTab
|
|
pTab = (*TIndex)(unsafe.Pointer(pIdx)).FpTable
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)) {
|
|
break
|
|
}
|
|
j = int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i)*2)))
|
|
if j == -int32(2) {
|
|
pExpr = (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FaColExpr + 8 + uintptr(i)*32))).FpExpr
|
|
} else {
|
|
if j >= 0 && libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(j)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) != 0 {
|
|
pExpr = _sqlite3ColumnExpr(tls, pTab, (*TTable)(unsafe.Pointer(pTab)).FaCol+uintptr(j)*16)
|
|
} else {
|
|
goto _1
|
|
}
|
|
}
|
|
if _sqlite3ExprIsConstant(tls, uintptr(0), pExpr) != 0 {
|
|
goto _1
|
|
}
|
|
p = _sqlite3DbMallocRaw(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(32))
|
|
if p == uintptr(0) {
|
|
break
|
|
}
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FpIENext = (*TParse)(unsafe.Pointer(pParse)).FpIdxEpr
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FpExpr = _sqlite3ExprDup(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pExpr, 0)
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FiDataCur = (*TSrcItem)(unsafe.Pointer(pTabItem)).FiCursor
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FiIdxCur = iIdxCur
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FiIdxCol = i
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FbMaybeNullRow = libc.BoolUint8(libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pTabItem)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_LEFT)|libc.Int32FromInt32(JT_LTORJ)|libc.Int32FromInt32(JT_RIGHT)) != 0)
|
|
if _sqlite3IndexAffinityStr(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pIdx) != 0 {
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).Faff = uint8(**(**uint8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FzColAff + uintptr(i))))
|
|
}
|
|
(*TParse)(unsafe.Pointer(pParse)).FpIdxEpr = p
|
|
if (*TIndexedExpr)(unsafe.Pointer(p)).FpIENext == uintptr(0) {
|
|
pArg = pParse + 104
|
|
_sqlite3ParserAddCleanup(tls, pParse, __ccgo_fp(_whereIndexedExprCleanup), pArg)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called for a partial index - one with a WHERE clause - in
|
|
// ** two scenarios. In both cases, it determines whether or not the WHERE
|
|
// ** clause on the index implies that a column of the table may be safely
|
|
// ** replaced by a constant expression. For example, in the following
|
|
// ** SELECT:
|
|
// **
|
|
// ** CREATE INDEX i1 ON t1(b, c) WHERE a=<expr>;
|
|
// ** SELECT a, b, c FROM t1 WHERE a=<expr> AND b=?;
|
|
// **
|
|
// ** The "a" in the select-list may be replaced by <expr>, iff:
|
|
// **
|
|
// ** (a) <expr> is a constant expression, and
|
|
// ** (b) The (a=<expr>) comparison uses the BINARY collation sequence, and
|
|
// ** (c) Column "a" has an affinity other than NONE or BLOB.
|
|
// **
|
|
// ** If argument pItem is NULL, then pMask must not be NULL. In this case this
|
|
// ** function is being called as part of determining whether or not pIdx
|
|
// ** is a covering index. This function clears any bits in (*pMask)
|
|
// ** corresponding to columns that may be replaced by constants as described
|
|
// ** above.
|
|
// **
|
|
// ** Otherwise, if pItem is not NULL, then this function is being called
|
|
// ** as part of coding a loop that uses index pIdx. In this case, add entries
|
|
// ** to the Parse.pIdxPartExpr list for each column that can be replaced
|
|
// ** by a constant.
|
|
// */
|
|
func _wherePartIdxExpr(tls *libc.TLS, pParse uintptr, pIdx uintptr, pPart uintptr, pMask uintptr, iIdxCur int32, pItem uintptr) {
|
|
var aff Tu8
|
|
var bNullRow int32
|
|
var db, p, pArg, pLeft, pRight uintptr
|
|
_, _, _, _, _, _, _ = aff, bNullRow, db, p, pArg, pLeft, pRight
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pPart)).Fop) == int32(TK_AND) {
|
|
_wherePartIdxExpr(tls, pParse, pIdx, (*TExpr)(unsafe.Pointer(pPart)).FpRight, pMask, iIdxCur, pItem)
|
|
pPart = (*TExpr)(unsafe.Pointer(pPart)).FpLeft
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pPart)).Fop) == int32(TK_EQ) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pPart)).Fop) == int32(TK_IS) {
|
|
pLeft = (*TExpr)(unsafe.Pointer(pPart)).FpLeft
|
|
pRight = (*TExpr)(unsafe.Pointer(pPart)).FpRight
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pLeft)).Fop) != int32(TK_COLUMN) {
|
|
return
|
|
}
|
|
if !(_sqlite3ExprIsConstant(tls, uintptr(0), pRight) != 0) {
|
|
return
|
|
}
|
|
if !(_sqlite3IsBinary(tls, _sqlite3ExprCompareCollSeq(tls, pParse, pPart)) != 0) {
|
|
return
|
|
}
|
|
if int32((*TExpr)(unsafe.Pointer(pLeft)).FiColumn) < 0 {
|
|
return
|
|
}
|
|
aff = uint8((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FpTable)).FaCol + uintptr((*TExpr)(unsafe.Pointer(pLeft)).FiColumn)*16))).Faffinity)
|
|
if libc.Int32FromUint8(aff) >= int32(SQLITE_AFF_TEXT) {
|
|
if pItem != 0 {
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
p = _sqlite3DbMallocRaw(tls, db, uint64(32))
|
|
if p != 0 {
|
|
bNullRow = libc.BoolInt32(libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pItem)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_LEFT)|libc.Int32FromInt32(JT_LTORJ)) != 0)
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FpExpr = _sqlite3ExprDup(tls, db, pRight, 0)
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FiDataCur = (*TSrcItem)(unsafe.Pointer(pItem)).FiCursor
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FiIdxCur = iIdxCur
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FiIdxCol = int32((*TExpr)(unsafe.Pointer(pLeft)).FiColumn)
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FbMaybeNullRow = libc.Uint8FromInt32(bNullRow)
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).FpIENext = (*TParse)(unsafe.Pointer(pParse)).FpIdxPartExpr
|
|
(*TIndexedExpr)(unsafe.Pointer(p)).Faff = aff
|
|
(*TParse)(unsafe.Pointer(pParse)).FpIdxPartExpr = p
|
|
if (*TIndexedExpr)(unsafe.Pointer(p)).FpIENext == uintptr(0) {
|
|
pArg = pParse + 112
|
|
_sqlite3ParserAddCleanup(tls, pParse, __ccgo_fp(_whereIndexedExprCleanup), pArg)
|
|
}
|
|
}
|
|
} else {
|
|
if int32((*TExpr)(unsafe.Pointer(pLeft)).FiColumn) < libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8))-libc.Int32FromInt32(1) {
|
|
**(**TBitmask)(__ccgo_up(pMask)) &= ^(libc.Uint64FromInt32(1) << (*TExpr)(unsafe.Pointer(pLeft)).FiColumn)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called to estimate the number of rows visited by a
|
|
// ** range-scan on a skip-scan index. For example:
|
|
// **
|
|
// ** CREATE INDEX i1 ON t1(a, b, c);
|
|
// ** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?;
|
|
// **
|
|
// ** Value pLoop->nOut is currently set to the estimated number of rows
|
|
// ** visited for scanning (a=? AND b=?). This function reduces that estimate
|
|
// ** by some factor to account for the (c BETWEEN ? AND ?) expression based
|
|
// ** on the stat4 data for the index. this scan will be performed multiple
|
|
// ** times (once for each (a,b) combination that matches a=?) is dealt with
|
|
// ** by the caller.
|
|
// **
|
|
// ** It does this by scanning through all stat4 samples, comparing values
|
|
// ** extracted from pLower and pUpper with the corresponding column in each
|
|
// ** sample. If L and U are the number of samples found to be less than or
|
|
// ** equal to the values extracted from pLower and pUpper respectively, and
|
|
// ** N is the total number of samples, the pLoop->nOut value is adjusted
|
|
// ** as follows:
|
|
// **
|
|
// ** nOut = nOut * ( min(U - L, 1) / N )
|
|
// **
|
|
// ** If pLower is NULL, or a value cannot be extracted from the term, L is
|
|
// ** set to zero. If pUpper is NULL, or a value cannot be extracted from it,
|
|
// ** U is set to N.
|
|
// **
|
|
// ** Normally, this function sets *pbDone to 1 before returning. However,
|
|
// ** if no value can be extracted from either pLower or pUpper (and so the
|
|
// ** estimate of the number of rows delivered remains unchanged), *pbDone
|
|
// ** is left as is.
|
|
// **
|
|
// ** If an error occurs, an SQLite error code is returned. Otherwise,
|
|
// ** SQLITE_OK.
|
|
// */
|
|
func _whereRangeSkipScanEst(tls *libc.TLS, pParse uintptr, pLower uintptr, pUpper uintptr, pLoop uintptr, pbDone uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var aff Tu8
|
|
var db, p, pColl, v3 uintptr
|
|
var i, nAdjust, nDiff, nEq, nLower, nUpper, rc, res, res1, v1 int32
|
|
var _ /* p1 at bp+0 */ uintptr
|
|
var _ /* p2 at bp+8 */ uintptr
|
|
var _ /* pVal at bp+16 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = aff, db, i, nAdjust, nDiff, nEq, nLower, nUpper, p, pColl, rc, res, res1, v1, v3
|
|
p = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex
|
|
nEq = libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
nLower = -int32(1)
|
|
nUpper = (*TIndex)(unsafe.Pointer(p)).FnSample + int32(1)
|
|
rc = SQLITE_OK
|
|
aff = _sqlite3IndexColumnAffinity(tls, db, p, nEq)
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* Value extracted from pLower */
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0) /* Value extracted from pUpper */
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0) /* Value extracted from record */
|
|
pColl = _sqlite3LocateCollSeq(tls, pParse, **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(p)).FazColl + uintptr(nEq)*8)))
|
|
if pLower != 0 {
|
|
rc = _sqlite3Stat4ValueFromExpr(tls, pParse, (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pLower)).FpExpr)).FpRight, aff, bp)
|
|
nLower = 0
|
|
}
|
|
if pUpper != 0 && rc == SQLITE_OK {
|
|
rc = _sqlite3Stat4ValueFromExpr(tls, pParse, (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pUpper)).FpExpr)).FpRight, aff, bp+8)
|
|
if **(**uintptr)(__ccgo_up(bp + 8)) != 0 {
|
|
v1 = 0
|
|
} else {
|
|
v1 = (*TIndex)(unsafe.Pointer(p)).FnSample
|
|
}
|
|
nUpper = v1
|
|
}
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 || **(**uintptr)(__ccgo_up(bp + 8)) != 0 {
|
|
i = 0
|
|
for {
|
|
if !(rc == SQLITE_OK && i < (*TIndex)(unsafe.Pointer(p)).FnSample) {
|
|
break
|
|
}
|
|
rc = _sqlite3Stat4Column(tls, db, (**(**TIndexSample)(__ccgo_up((*TIndex)(unsafe.Pointer(p)).FaSample + uintptr(i)*40))).Fp, (**(**TIndexSample)(__ccgo_up((*TIndex)(unsafe.Pointer(p)).FaSample + uintptr(i)*40))).Fn, nEq, bp+16)
|
|
if rc == SQLITE_OK && **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
res = _sqlite3MemCompare(tls, **(**uintptr)(__ccgo_up(bp)), **(**uintptr)(__ccgo_up(bp + 16)), pColl)
|
|
if res >= 0 {
|
|
nLower = nLower + 1
|
|
}
|
|
}
|
|
if rc == SQLITE_OK && **(**uintptr)(__ccgo_up(bp + 8)) != 0 {
|
|
res1 = _sqlite3MemCompare(tls, **(**uintptr)(__ccgo_up(bp + 8)), **(**uintptr)(__ccgo_up(bp + 16)), pColl)
|
|
if res1 >= 0 {
|
|
nUpper = nUpper + 1
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
nDiff = nUpper - nLower
|
|
if nDiff <= 0 {
|
|
nDiff = int32(1)
|
|
}
|
|
/* If there is both an upper and lower bound specified, and the
|
|
** comparisons indicate that they are close together, use the fallback
|
|
** method (assume that the scan visits 1/64 of the rows) for estimating
|
|
** the number of rows visited. Otherwise, estimate the number of rows
|
|
** using the method described in the header comment for this function. */
|
|
if nDiff != int32(1) || pUpper == uintptr(0) || pLower == uintptr(0) {
|
|
nAdjust = int32(_sqlite3LogEst(tls, libc.Uint64FromInt32((*TIndex)(unsafe.Pointer(p)).FnSample))) - int32(_sqlite3LogEst(tls, libc.Uint64FromInt32(nDiff)))
|
|
v3 = pLoop + 22
|
|
*(*TLogEst)(unsafe.Pointer(v3)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v3))) - nAdjust)
|
|
**(**int32)(__ccgo_up(pbDone)) = int32(1)
|
|
}
|
|
} else {
|
|
}
|
|
_sqlite3ValueFree(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
_sqlite3ValueFree(tls, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
_sqlite3ValueFree(tls, **(**uintptr)(__ccgo_up(bp + 16)))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Term pTerm is a vector range comparison operation. The first comparison
|
|
// ** in the vector can be optimized using column nEq of the index. This
|
|
// ** function returns the total number of vector elements that can be used
|
|
// ** as part of the range comparison.
|
|
// **
|
|
// ** For example, if the query is:
|
|
// **
|
|
// ** WHERE a = ? AND (b, c, d) > (?, ?, ?)
|
|
// **
|
|
// ** and the index:
|
|
// **
|
|
// ** CREATE INDEX ... ON (a, b, c, d, e)
|
|
// **
|
|
// ** then this function would be invoked with nEq=1. The value returned in
|
|
// ** this case is 3.
|
|
// */
|
|
func _whereRangeVectorLen(tls *libc.TLS, pParse uintptr, iCur int32, pIdx uintptr, nEq int32, pTerm uintptr) (r int32) {
|
|
var aff, idxaff uint8
|
|
var i, nCmp, v1 int32
|
|
var pColl, pLhs, pRhs, t uintptr
|
|
_, _, _, _, _, _, _, _, _ = aff, i, idxaff, nCmp, pColl, pLhs, pRhs, t, v1
|
|
nCmp = _sqlite3ExprVectorSize(tls, (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).FpLeft)
|
|
if nCmp < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)-nEq {
|
|
v1 = nCmp
|
|
} else {
|
|
v1 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn) - nEq
|
|
}
|
|
nCmp = v1
|
|
i = int32(1)
|
|
for {
|
|
if !(i < nCmp) {
|
|
break
|
|
} /* Comparison affinity */
|
|
idxaff = uint8(0)
|
|
pLhs = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).FpLeft + 32)) + 8 + uintptr(i)*32))).FpExpr
|
|
pRhs = (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).FpRight
|
|
if (*TExpr)(unsafe.Pointer(pRhs)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
pRhs = (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pRhs + 32)))).FpEList + 8 + uintptr(i)*32))).FpExpr
|
|
} else {
|
|
pRhs = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pRhs + 32)) + 8 + uintptr(i)*32))).FpExpr
|
|
}
|
|
/* Check that the LHS of the comparison is a column reference to
|
|
** the right column of the right source table. And that the sort
|
|
** order of the index column is the same as the sort order of the
|
|
** leftmost index column. */
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pLhs)).Fop) != int32(TK_COLUMN) || (*TExpr)(unsafe.Pointer(pLhs)).FiTable != iCur || int32((*TExpr)(unsafe.Pointer(pLhs)).FiColumn) != int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i+nEq)*2))) || libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaSortOrder + uintptr(i+nEq)))) != libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaSortOrder + uintptr(nEq)))) {
|
|
break
|
|
}
|
|
aff = _sqlite3CompareAffinity(tls, pRhs, _sqlite3ExprAffinity(tls, pLhs))
|
|
idxaff = _sqlite3TableColumnAffinity(tls, (*TIndex)(unsafe.Pointer(pIdx)).FpTable, int32((*TExpr)(unsafe.Pointer(pLhs)).FiColumn))
|
|
if libc.Int32FromUint8(aff) != libc.Int32FromUint8(idxaff) {
|
|
break
|
|
}
|
|
if (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Commuted)) != uint32(0) {
|
|
t = pRhs
|
|
pRhs = pLhs
|
|
pLhs = t
|
|
}
|
|
pColl = _sqlite3BinaryCompareCollSeq(tls, pParse, pLhs, pRhs)
|
|
if pColl == uintptr(0) {
|
|
break
|
|
}
|
|
if _sqlite3StrICmp(tls, (*TCollSeq)(unsafe.Pointer(pColl)).FzName, **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FazColl + uintptr(i+nEq)*8))) != 0 {
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return i
|
|
}
|
|
|
|
/*
|
|
** Adjust the cost C by the costMult factor T. This only occurs if
|
|
** compiled with -DSQLITE_ENABLE_COSTMULT
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize a WHERE clause scanner object. Return a pointer to the
|
|
// ** first match. Return NULL if there are no matches.
|
|
// **
|
|
// ** The scanner will be searching the WHERE clause pWC. It will look
|
|
// ** for terms of the form "X <op> <expr>" where X is column iColumn of table
|
|
// ** iCur. Or if pIdx!=0 then X is column iColumn of index pIdx. pIdx
|
|
// ** must be one of the indexes of table iCur.
|
|
// **
|
|
// ** The <op> must be one of the operators described by opMask.
|
|
// **
|
|
// ** If the search is for X and the WHERE clause contains terms of the
|
|
// ** form X=Y then this routine might also return terms of the form
|
|
// ** "Y <op> <expr>". The number of levels of transitivity is limited,
|
|
// ** but is enough to handle most commonly occurring SQL statements.
|
|
// **
|
|
// ** If X is not the INTEGER PRIMARY KEY then X must be compatible with
|
|
// ** index pIdx.
|
|
// */
|
|
func _whereScanInit(tls *libc.TLS, pScan uintptr, pWC uintptr, iCur int32, iColumn int32, opMask Tu32, pIdx uintptr) (r uintptr) {
|
|
var j int32
|
|
_ = j
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FpOrigWC = pWC
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FpWC = pWC
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FpIdxExpr = uintptr(0)
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).Fidxaff = uint8(0)
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FzCollName = uintptr(0)
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FopMask = opMask
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).Fk = 0
|
|
**(**int32)(__ccgo_up(pScan + 44)) = iCur
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FnEquiv = uint8(1)
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FiEquiv = uint8(1)
|
|
if pIdx != 0 {
|
|
j = iColumn
|
|
iColumn = int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(j)*2)))
|
|
if iColumn == int32((*TTable)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FpTable)).FiPKey) {
|
|
iColumn = -int32(1)
|
|
} else {
|
|
if iColumn >= 0 {
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).Fidxaff = (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FpTable)).FaCol + uintptr(iColumn)*16))).Faffinity
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FzCollName = **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FazColl + uintptr(j)*8))
|
|
} else {
|
|
if iColumn == -int32(2) {
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FpIdxExpr = (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FaColExpr + 8 + uintptr(j)*32))).FpExpr
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FzCollName = **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FazColl + uintptr(j)*8))
|
|
**(**Ti16)(__ccgo_up(pScan + 88)) = int16(-libc.Int32FromInt32(2))
|
|
return _whereScanInitIndexExpr(tls, pScan)
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if iColumn == -int32(2) {
|
|
return uintptr(0)
|
|
}
|
|
}
|
|
**(**Ti16)(__ccgo_up(pScan + 88)) = int16(iColumn)
|
|
return _whereScanNext(tls, pScan)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance to the next WhereTerm that matches according to the criteria
|
|
// ** established when the pScan object was initialized by whereScanInit().
|
|
// ** Return NULL if there are no more matching WhereTerms.
|
|
// */
|
|
func _whereScanNext(tls *libc.TLS, pScan uintptr) (r uintptr) {
|
|
var iColumn Ti16
|
|
var iCur, j, k int32
|
|
var pColl, pParse, pTerm, pWC, pX, zCollName, v2 uintptr
|
|
var v3 bool
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = iColumn, iCur, j, k, pColl, pParse, pTerm, pWC, pX, zCollName, v2, v3 /* The term being tested */
|
|
k = (*TWhereScan)(unsafe.Pointer(pScan)).Fk /* Where to start scanning */
|
|
pWC = (*TWhereScan)(unsafe.Pointer(pScan)).FpWC
|
|
for int32(1) != 0 {
|
|
iColumn = **(**Ti16)(__ccgo_up(pScan + 88 + uintptr(libc.Int32FromUint8((*TWhereScan)(unsafe.Pointer(pScan)).FiEquiv)-int32(1))*2))
|
|
iCur = **(**int32)(__ccgo_up(pScan + 44 + uintptr(libc.Int32FromUint8((*TWhereScan)(unsafe.Pointer(pScan)).FiEquiv)-int32(1))*4))
|
|
for cond := true; cond; cond = pWC != uintptr(0) {
|
|
pTerm = (*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(k)*56
|
|
for {
|
|
if !(k < (*TWhereClause)(unsafe.Pointer(pWC)).FnTerm) {
|
|
break
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(pTerm)).FleftCursor == iCur && (*(*struct {
|
|
FleftColumn int32
|
|
FiField int32
|
|
})(unsafe.Pointer(pTerm + 32))).FleftColumn == int32(iColumn) && (int32(iColumn) != -int32(2) || _sqlite3ExprCompareSkip(tls, (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).FpLeft, (*TWhereScan)(unsafe.Pointer(pScan)).FpIdxExpr, iCur) == 0) && (libc.Int32FromUint8((*TWhereScan)(unsafe.Pointer(pScan)).FiEquiv) <= int32(1) || !((*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != libc.Uint32FromInt32(0))) {
|
|
if v3 = libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&int32(WO_EQUIV) != 0 && libc.Int32FromUint8((*TWhereScan)(unsafe.Pointer(pScan)).FnEquiv) < libc.Int32FromUint64(libc.Uint64FromInt64(44)/libc.Uint64FromInt64(4)); v3 {
|
|
v2 = _whereRightSubexprIsColumn(tls, (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)
|
|
pX = v2
|
|
}
|
|
if v3 && v2 != uintptr(0) {
|
|
j = 0
|
|
for {
|
|
if !(j < libc.Int32FromUint8((*TWhereScan)(unsafe.Pointer(pScan)).FnEquiv)) {
|
|
break
|
|
}
|
|
if **(**int32)(__ccgo_up(pScan + 44 + uintptr(j)*4)) == (*TExpr)(unsafe.Pointer(pX)).FiTable && int32(**(**Ti16)(__ccgo_up(pScan + 88 + uintptr(j)*2))) == int32((*TExpr)(unsafe.Pointer(pX)).FiColumn) {
|
|
break
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
j = j + 1
|
|
}
|
|
if j == libc.Int32FromUint8((*TWhereScan)(unsafe.Pointer(pScan)).FnEquiv) {
|
|
**(**int32)(__ccgo_up(pScan + 44 + uintptr(j)*4)) = (*TExpr)(unsafe.Pointer(pX)).FiTable
|
|
**(**Ti16)(__ccgo_up(pScan + 88 + uintptr(j)*2)) = (*TExpr)(unsafe.Pointer(pX)).FiColumn
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FnEquiv = (*TWhereScan)(unsafe.Pointer(pScan)).FnEquiv + 1
|
|
}
|
|
}
|
|
if uint32((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&(*TWhereScan)(unsafe.Pointer(pScan)).FopMask != uint32(0) {
|
|
/* Verify the affinity and collating sequence match */
|
|
if (*TWhereScan)(unsafe.Pointer(pScan)).FzCollName != 0 && libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&int32(WO_ISNULL) == 0 {
|
|
pParse = (*TWhereInfo)(unsafe.Pointer((*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo)).FpParse
|
|
pX = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&int32(WO_IN) != 0 {
|
|
zCollName = _indexInAffinityOk(tls, pParse, pTerm, (*TWhereScan)(unsafe.Pointer(pScan)).Fidxaff)
|
|
if !(zCollName != 0) {
|
|
goto _1
|
|
}
|
|
} else {
|
|
if !(_sqlite3IndexAffinityOk(tls, pX, (*TWhereScan)(unsafe.Pointer(pScan)).Fidxaff) != 0) {
|
|
goto _1
|
|
}
|
|
pColl = _sqlite3ExprCompareCollSeq(tls, pParse, pX)
|
|
if pColl != 0 {
|
|
v2 = (*TCollSeq)(unsafe.Pointer(pColl)).FzName
|
|
} else {
|
|
v2 = uintptr(unsafe.Pointer(&_sqlite3StrBINARY))
|
|
}
|
|
zCollName = v2
|
|
}
|
|
if _sqlite3StrICmp(tls, zCollName, (*TWhereScan)(unsafe.Pointer(pScan)).FzCollName) != 0 {
|
|
goto _1
|
|
}
|
|
}
|
|
if v3 = libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_IS)) != 0; v3 {
|
|
pX = (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).FpRight
|
|
}
|
|
if v3 && pX != libc.UintptrFromInt32(0) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pX)).Fop) == int32(TK_COLUMN) && (*TExpr)(unsafe.Pointer(pX)).FiTable == **(**int32)(__ccgo_up(pScan + 44)) && int32((*TExpr)(unsafe.Pointer(pX)).FiColumn) == int32(**(**Ti16)(__ccgo_up(pScan + 88))) {
|
|
goto _1
|
|
}
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FpWC = pWC
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).Fk = k + int32(1)
|
|
return pTerm
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
k = k + 1
|
|
pTerm += 56
|
|
}
|
|
pWC = (*TWhereClause)(unsafe.Pointer(pWC)).FpOuter
|
|
k = 0
|
|
}
|
|
if libc.Int32FromUint8((*TWhereScan)(unsafe.Pointer(pScan)).FiEquiv) >= libc.Int32FromUint8((*TWhereScan)(unsafe.Pointer(pScan)).FnEquiv) {
|
|
break
|
|
}
|
|
pWC = (*TWhereScan)(unsafe.Pointer(pScan)).FpOrigWC
|
|
k = 0
|
|
(*TWhereScan)(unsafe.Pointer(pScan)).FiEquiv = (*TWhereScan)(unsafe.Pointer(pScan)).FiEquiv + 1
|
|
}
|
|
return uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Write the supplied super-journal name into the journal file for pager
|
|
// ** pPager at the current location. The super-journal name must be the last
|
|
// ** thing written to a journal file. If the pager is in full-sync mode, the
|
|
// ** journal file descriptor is advanced to the next sector boundary before
|
|
// ** anything is written. The format is:
|
|
// **
|
|
// ** + 4 bytes: PAGER_SJ_PGNO.
|
|
// ** + N bytes: super-journal filename in utf-8.
|
|
// ** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator).
|
|
// ** + 4 bytes: super-journal name checksum.
|
|
// ** + 8 bytes: aJournalMagic[].
|
|
// **
|
|
// ** The super-journal page checksum is the sum of the bytes in the super-journal
|
|
// ** name, where each byte is interpreted as a signed 8-bit integer.
|
|
// **
|
|
// ** If zSuper is a NULL pointer (occurs for a single database transaction),
|
|
// ** this call is a no-op.
|
|
// */
|
|
func _writeSuperJournal(tls *libc.TLS, pPager uintptr, zSuper uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var cksum Tu32
|
|
var iHdrOff Ti64
|
|
var nSuper, rc, v2, v3, v5, v7, v9 int32
|
|
var v10, v4, v6, v8 bool
|
|
var _ /* jrnlSize at bp+0 */ Ti64
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _ = cksum, iHdrOff, nSuper, rc, v10, v2, v3, v4, v5, v6, v7, v8, v9 /* Size of journal file on disk */
|
|
cksum = uint32(0) /* Checksum of string zSuper */
|
|
if !(zSuper != 0) || libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) == int32(PAGER_JOURNALMODE_MEMORY) || !((*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != libc.UintptrFromInt32(0)) {
|
|
return SQLITE_OK
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FsetSuper = uint8(1)
|
|
/* Calculate the length in bytes and the checksum of zSuper */
|
|
nSuper = 0
|
|
for {
|
|
if !(**(**uint8)(__ccgo_up(zSuper + uintptr(nSuper))) != 0) {
|
|
break
|
|
}
|
|
cksum = cksum + uint32(**(**uint8)(__ccgo_up(zSuper + uintptr(nSuper))))
|
|
goto _1
|
|
_1:
|
|
;
|
|
nSuper = nSuper + 1
|
|
}
|
|
/* If in full-sync mode, advance to the next disk sector before writing
|
|
** the super-journal name. This is in case the previous page written to
|
|
** the journal has already been synced.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FfullSync != 0 {
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = _journalHdrOffset(tls, pPager)
|
|
}
|
|
iHdrOff = (*TPager)(unsafe.Pointer(pPager)).FjournalOff
|
|
/* Write the super-journal data to the end of the journal file. If
|
|
** an error occurs, return the error code to the caller.
|
|
*/
|
|
v2 = _write32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iHdrOff, (*TPager)(unsafe.Pointer(pPager)).FlckPgno)
|
|
rc = v2
|
|
if v4 = 0 != v2; !v4 {
|
|
v3 = _sqlite3OsWrite(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, zSuper, nSuper, iHdrOff+int64(4))
|
|
rc = v3
|
|
}
|
|
if v6 = v4 || 0 != v3; !v6 {
|
|
v5 = _write32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iHdrOff+int64(4)+int64(nSuper), libc.Uint32FromInt32(nSuper))
|
|
rc = v5
|
|
}
|
|
if v8 = v6 || 0 != v5; !v8 {
|
|
v7 = _write32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iHdrOff+int64(4)+int64(nSuper)+int64(4), cksum)
|
|
rc = v7
|
|
}
|
|
if v10 = v8 || 0 != v7; !v10 {
|
|
v9 = _sqlite3OsWrite(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, uintptr(unsafe.Pointer(&_aJournalMagic)), int32(8), iHdrOff+int64(4)+int64(nSuper)+int64(8))
|
|
rc = v9
|
|
}
|
|
if v10 || 0 != v9 {
|
|
return rc
|
|
}
|
|
**(**Ti64)(__ccgo_up(pPager + 96)) += int64(nSuper + libc.Int32FromInt32(20))
|
|
/* If the pager is in persistent-journal mode, then the physical
|
|
** journal-file may extend past the end of the super-journal name
|
|
** and 8 bytes of magic data just written to the file. This is
|
|
** dangerous because the code to rollback a hot-journal file
|
|
** will not be able to find the super-journal name to determine
|
|
** whether or not the journal is hot.
|
|
**
|
|
** Easiest thing to do in this scenario is to truncate the journal
|
|
** file to the required size.
|
|
*/
|
|
v2 = _sqlite3OsFileSize(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, bp)
|
|
rc = v2
|
|
if SQLITE_OK == v2 && **(**Ti64)(__ccgo_up(bp)) > (*TPager)(unsafe.Pointer(pPager)).FjournalOff {
|
|
rc = _sqlite3OsTruncate(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, (*TPager)(unsafe.Pointer(pPager)).FjournalOff)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Attempt the transfer optimization on INSERTs of the form
|
|
// **
|
|
// ** INSERT INTO tab1 SELECT * FROM tab2;
|
|
// **
|
|
// ** The xfer optimization transfers raw records from tab2 over to tab1.
|
|
// ** Columns are not decoded and reassembled, which greatly improves
|
|
// ** performance. Raw index records are transferred in the same way.
|
|
// **
|
|
// ** The xfer optimization is only attempted if tab1 and tab2 are compatible.
|
|
// ** There are lots of rules for determining compatibility - see comments
|
|
// ** embedded in the code for details.
|
|
// **
|
|
// ** This routine returns TRUE if the optimization is guaranteed to be used.
|
|
// ** Sometimes the xfer optimization will only work if the destination table
|
|
// ** is empty - a factor that can only be determined at run-time. In that
|
|
// ** case, this routine generates code for the xfer optimization but also
|
|
// ** does a test to see if the destination table is empty and jumps over the
|
|
// ** xfer optimization code if the test fails. In that case, this routine
|
|
// ** returns FALSE so that the caller will know to go ahead and generate
|
|
// ** an unoptimized transfer. This routine also returns FALSE if there
|
|
// ** is no chance that the xfer optimization can be applied.
|
|
// **
|
|
// ** This optimization is particularly useful at making VACUUM run faster.
|
|
// */
|
|
func _xferOptimization(tls *libc.TLS, pParse uintptr, pDest uintptr, pSelect uintptr, onError int32, iDbDest int32) (r int32) {
|
|
var addr1, addr2, destHasUniqueIdx, emptyDestTest, emptySrcTest, i, iDbSrc, iDest, iSrc, regAutoinc, regData, regRowid, v4 int32
|
|
var db, pDestCol, pDestExpr, pDestIdx, pEList, pItem, pSrc, pSrcCol, pSrcExpr, pSrcIdx, v, zColl, v5 uintptr
|
|
var idxInsFlags, insFlags Tu8
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addr1, addr2, db, destHasUniqueIdx, emptyDestTest, emptySrcTest, i, iDbSrc, iDest, iSrc, idxInsFlags, insFlags, pDestCol, pDestExpr, pDestIdx, pEList, pItem, pSrc, pSrcCol, pSrcExpr, pSrcIdx, regAutoinc, regData, regRowid, v, zColl, v4, v5
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* Loop addresses */
|
|
emptyDestTest = 0 /* Address of test for empty pDest */
|
|
emptySrcTest = 0 /* Memory register used by AUTOINC */
|
|
destHasUniqueIdx = 0 /* Registers holding data and rowid */
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpWith != 0 || (*TSelect)(unsafe.Pointer(pSelect)).FpWith != 0 {
|
|
/* Do not attempt to process this query if there are an WITH clauses
|
|
** attached to it. Proceeding may generate a false "no such table: xxx"
|
|
** error if pSelect reads from a CTE named "xxx". */
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pDest)).FeTabType) == int32(TABTYP_VTAB) {
|
|
return 0 /* tab1 must not be a virtual table */
|
|
}
|
|
if onError == int32(OE_Default) {
|
|
if int32((*TTable)(unsafe.Pointer(pDest)).FiPKey) >= 0 {
|
|
onError = libc.Int32FromUint8((*TTable)(unsafe.Pointer(pDest)).FkeyConf)
|
|
}
|
|
if onError == int32(OE_Default) {
|
|
onError = int32(OE_Abort)
|
|
}
|
|
}
|
|
/* allocated even if there is no FROM clause */
|
|
if (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpSrc)).FnSrc != int32(1) {
|
|
return 0 /* FROM clause must have exactly one term */
|
|
}
|
|
if int32(*(*uint32)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpSrc + 8 + 24 + 4))&0x4>>2) != 0 {
|
|
return 0 /* FROM clause cannot contain a subquery */
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSelect)).FpWhere != 0 {
|
|
return 0 /* SELECT may not have a WHERE clause */
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSelect)).FpOrderBy != 0 {
|
|
return 0 /* SELECT may not have an ORDER BY clause */
|
|
}
|
|
/* Do not need to test for a HAVING clause. If HAVING is present but
|
|
** there is no ORDER BY, we will get an error. */
|
|
if (*TSelect)(unsafe.Pointer(pSelect)).FpGroupBy != 0 {
|
|
return 0 /* SELECT may not have a GROUP BY clause */
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSelect)).FpLimit != 0 {
|
|
return 0 /* SELECT may not have a LIMIT clause */
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSelect)).FpPrior != 0 {
|
|
return 0 /* SELECT may not be a compound query */
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSelect)).FselFlags&uint32(SF_Distinct) != 0 {
|
|
return 0 /* SELECT may not be DISTINCT */
|
|
}
|
|
pEList = (*TSelect)(unsafe.Pointer(pSelect)).FpEList
|
|
if (*TExprList)(unsafe.Pointer(pEList)).FnExpr != int32(1) {
|
|
return 0 /* The result set must have exactly one column */
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer((*(*TExprList_item)(unsafe.Pointer(pEList + 8))).FpExpr)).Fop) != int32(TK_ASTERISK) {
|
|
return 0 /* The result set must be the special operator "*" */
|
|
}
|
|
/* At this point we have established that the statement is of the
|
|
** correct syntactic form to participate in this optimization. Now
|
|
** we have to check the semantics.
|
|
*/
|
|
pItem = (*TSelect)(unsafe.Pointer(pSelect)).FpSrc + 8
|
|
pSrc = _sqlite3LocateTableItem(tls, pParse, uint32(0), pItem)
|
|
if pSrc == uintptr(0) {
|
|
return 0 /* FROM clause does not contain a real table */
|
|
}
|
|
if (*TTable)(unsafe.Pointer(pSrc)).Ftnum == (*TTable)(unsafe.Pointer(pDest)).Ftnum && (*TTable)(unsafe.Pointer(pSrc)).FpSchema == (*TTable)(unsafe.Pointer(pDest)).FpSchema {
|
|
/* Possible due to bad sqlite_schema.rootpage */
|
|
return 0 /* tab1 and tab2 may not be the same table */
|
|
}
|
|
if libc.BoolInt32((*TTable)(unsafe.Pointer(pDest)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0)) != libc.BoolInt32((*TTable)(unsafe.Pointer(pSrc)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0)) {
|
|
return 0 /* source and destination must both be WITHOUT ROWID or not */
|
|
}
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pSrc)).FeTabType) == libc.Int32FromInt32(TABTYP_NORM)) {
|
|
return 0 /* tab2 may not be a view or virtual table */
|
|
}
|
|
if int32((*TTable)(unsafe.Pointer(pDest)).FnCol) != int32((*TTable)(unsafe.Pointer(pSrc)).FnCol) {
|
|
return 0 /* Number of columns must be the same in tab1 and tab2 */
|
|
}
|
|
if int32((*TTable)(unsafe.Pointer(pDest)).FiPKey) != int32((*TTable)(unsafe.Pointer(pSrc)).FiPKey) {
|
|
return 0 /* Both tables must have the same INTEGER PRIMARY KEY */
|
|
}
|
|
if (*TTable)(unsafe.Pointer(pDest)).FtabFlags&uint32(TF_Strict) != uint32(0) && (*TTable)(unsafe.Pointer(pSrc)).FtabFlags&uint32(TF_Strict) == uint32(0) {
|
|
return 0 /* Cannot feed from a non-strict into a strict table */
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pDest)).FnCol)) {
|
|
break
|
|
}
|
|
pDestCol = (*TTable)(unsafe.Pointer(pDest)).FaCol + uintptr(i)*16
|
|
pSrcCol = (*TTable)(unsafe.Pointer(pSrc)).FaCol + uintptr(i)*16
|
|
/* Even if tables t1 and t2 have identical schemas, if they contain
|
|
** generated columns, then this statement is semantically incorrect:
|
|
**
|
|
** INSERT INTO t2 SELECT * FROM t1;
|
|
**
|
|
** The reason is that generated column values are returned by the
|
|
** the SELECT statement on the right but the INSERT statement on the
|
|
** left wants them to be omitted.
|
|
**
|
|
** Nevertheless, this is a useful notational shorthand to tell SQLite
|
|
** to do a bulk transfer all of the content from t1 over to t2.
|
|
**
|
|
** We could, in theory, disable this (except for internal use by the
|
|
** VACUUM command where it is actually needed). But why do that? It
|
|
** seems harmless enough, and provides a useful service.
|
|
*/
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pDestCol)).FcolFlags)&int32(COLFLAG_GENERATED) != libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pSrcCol)).FcolFlags)&int32(COLFLAG_GENERATED) {
|
|
return 0 /* Both columns have the same generated-column type */
|
|
}
|
|
/* But the transfer is only allowed if both the source and destination
|
|
** tables have the exact same expressions for generated columns.
|
|
** This requirement could be relaxed for VIRTUAL columns, I suppose.
|
|
*/
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pDestCol)).FcolFlags)&int32(COLFLAG_GENERATED) != 0 {
|
|
if _sqlite3ExprCompare(tls, uintptr(0), _sqlite3ColumnExpr(tls, pSrc, pSrcCol), _sqlite3ColumnExpr(tls, pDest, pDestCol), -int32(1)) != 0 {
|
|
return 0 /* Different generator expressions */
|
|
}
|
|
}
|
|
if libc.Int32FromUint8((*TColumn)(unsafe.Pointer(pDestCol)).Faffinity) != libc.Int32FromUint8((*TColumn)(unsafe.Pointer(pSrcCol)).Faffinity) {
|
|
return 0 /* Affinity must be the same on all columns */
|
|
}
|
|
if Xsqlite3_stricmp(tls, _sqlite3ColumnColl(tls, pDestCol), _sqlite3ColumnColl(tls, pSrcCol)) != 0 {
|
|
return 0 /* Collating sequence must be the same on all columns */
|
|
}
|
|
if int32(uint32(*(*uint8)(unsafe.Pointer(pDestCol + 8))&0xf>>0)) != 0 && !(int32(uint32(*(*uint8)(unsafe.Pointer(pSrcCol + 8))&0xf>>0)) != 0) {
|
|
return 0 /* tab2 must be NOT NULL if tab1 is */
|
|
}
|
|
/* Default values for second and subsequent columns need to match. */
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pDestCol)).FcolFlags)&int32(COLFLAG_GENERATED) == 0 && i > 0 {
|
|
pDestExpr = _sqlite3ColumnExpr(tls, pDest, pDestCol)
|
|
pSrcExpr = _sqlite3ColumnExpr(tls, pSrc, pSrcCol)
|
|
if libc.BoolInt32(pDestExpr == uintptr(0)) != libc.BoolInt32(pSrcExpr == uintptr(0)) || pDestExpr != uintptr(0) && libc.Xstrcmp(tls, *(*uintptr)(unsafe.Pointer(pDestExpr + 8)), *(*uintptr)(unsafe.Pointer(pSrcExpr + 8))) != 0 {
|
|
return 0 /* Default values must be the same for all columns */
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
pDestIdx = (*TTable)(unsafe.Pointer(pDest)).FpIndex
|
|
for {
|
|
if !(pDestIdx != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TIndex)(unsafe.Pointer(pDestIdx)).FonError) != OE_None {
|
|
destHasUniqueIdx = int32(1)
|
|
}
|
|
pSrcIdx = (*TTable)(unsafe.Pointer(pSrc)).FpIndex
|
|
for {
|
|
if !(pSrcIdx != 0) {
|
|
break
|
|
}
|
|
if _xferCompatibleIndex(tls, pDestIdx, pSrcIdx) != 0 {
|
|
break
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
pSrcIdx = (*TIndex)(unsafe.Pointer(pSrcIdx)).FpNext
|
|
}
|
|
if pSrcIdx == uintptr(0) {
|
|
return 0 /* pDestIdx has no corresponding index in pSrc */
|
|
}
|
|
if (*TIndex)(unsafe.Pointer(pSrcIdx)).Ftnum == (*TIndex)(unsafe.Pointer(pDestIdx)).Ftnum && (*TTable)(unsafe.Pointer(pSrc)).FpSchema == (*TTable)(unsafe.Pointer(pDest)).FpSchema && _sqlite3FaultSim(tls, int32(411)) == SQLITE_OK {
|
|
/* The sqlite3FaultSim() call allows this corruption test to be
|
|
** bypassed during testing, in order to exercise other corruption tests
|
|
** further downstream. */
|
|
return 0 /* Corrupt schema - two indexes on the same btree */
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pDestIdx = (*TIndex)(unsafe.Pointer(pDestIdx)).FpNext
|
|
}
|
|
if (*TTable)(unsafe.Pointer(pDest)).FpCheck != 0 && (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_Vacuum) == uint32(0) && _sqlite3ExprListCompare(tls, (*TTable)(unsafe.Pointer(pSrc)).FpCheck, (*TTable)(unsafe.Pointer(pDest)).FpCheck, -int32(1)) != 0 {
|
|
return 0 /* Tables have different CHECK constraints. Ticket #2252 */
|
|
}
|
|
/* Disallow the transfer optimization if the destination table contains
|
|
** any foreign key constraints. This is more restrictive than necessary.
|
|
** But the main beneficiary of the transfer optimization is the VACUUM
|
|
** command, and the VACUUM command disables foreign key constraints. So
|
|
** the extra complication to make this rule less restrictive is probably
|
|
** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
|
|
*/
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_ForeignKeys) != uint64(0) && (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pDest + 64))).FpFKey != uintptr(0) {
|
|
return 0
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Fflags&(libc.Uint64FromInt32(libc.Int32FromInt32(0x00001))<<libc.Int32FromInt32(32)) != uint64(0) {
|
|
return 0 /* xfer opt does not play well with PRAGMA count_changes */
|
|
}
|
|
/* If we get this far, it means that the xfer optimization is at
|
|
** least a possibility, though it might only work if the destination
|
|
** table (tab1) is initially empty.
|
|
*/
|
|
iDbSrc = _sqlite3SchemaToIndex(tls, db, (*TTable)(unsafe.Pointer(pSrc)).FpSchema)
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
_sqlite3CodeVerifySchema(tls, pParse, iDbSrc)
|
|
v5 = pParse + 56
|
|
v4 = *(*int32)(unsafe.Pointer(v5))
|
|
*(*int32)(unsafe.Pointer(v5)) = *(*int32)(unsafe.Pointer(v5)) + 1
|
|
iSrc = v4
|
|
v5 = pParse + 56
|
|
v4 = *(*int32)(unsafe.Pointer(v5))
|
|
*(*int32)(unsafe.Pointer(v5)) = *(*int32)(unsafe.Pointer(v5)) + 1
|
|
iDest = v4
|
|
regAutoinc = _autoIncBegin(tls, pParse, iDbDest, pDest)
|
|
regData = _sqlite3GetTempReg(tls, pParse)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Null), 0, regData)
|
|
regRowid = _sqlite3GetTempReg(tls, pParse)
|
|
_sqlite3OpenTable(tls, pParse, iDest, iDbDest, pDest, int32(OP_OpenWrite))
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_Vacuum) == uint32(0) && (int32((*TTable)(unsafe.Pointer(pDest)).FiPKey) < 0 && (*TTable)(unsafe.Pointer(pDest)).FpIndex != uintptr(0) || destHasUniqueIdx != 0 || onError != int32(OE_Abort) && onError != int32(OE_Rollback)) {
|
|
/* In some circumstances, we are able to run the xfer optimization
|
|
** only if the destination table is initially empty. Unless the
|
|
** DBFLAG_Vacuum flag is set, this block generates code to make
|
|
** that determination. If DBFLAG_Vacuum is set, then the destination
|
|
** table is always empty.
|
|
**
|
|
** Conditions under which the destination must be empty:
|
|
**
|
|
** (1) There is no INTEGER PRIMARY KEY but there are indices.
|
|
** (If the destination is not initially empty, the rowid fields
|
|
** of index entries might need to change.)
|
|
**
|
|
** (2) The destination has a unique index. (The xfer optimization
|
|
** is unable to test uniqueness.)
|
|
**
|
|
** (3) onError is something other than OE_Abort and OE_Rollback.
|
|
*/
|
|
addr1 = _sqlite3VdbeAddOp2(tls, v, int32(OP_Rewind), iDest, 0)
|
|
emptyDestTest = _sqlite3VdbeAddOp0(tls, v, int32(OP_Goto))
|
|
_sqlite3VdbeJumpHere(tls, v, addr1)
|
|
}
|
|
if (*TTable)(unsafe.Pointer(pSrc)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0) {
|
|
_sqlite3OpenTable(tls, pParse, iSrc, iDbSrc, pSrc, int32(OP_OpenRead))
|
|
emptySrcTest = _sqlite3VdbeAddOp2(tls, v, int32(OP_Rewind), iSrc, 0)
|
|
if int32((*TTable)(unsafe.Pointer(pDest)).FiPKey) >= 0 {
|
|
addr1 = _sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), iSrc, regRowid)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_Vacuum) == uint32(0) {
|
|
addr2 = _sqlite3VdbeAddOp3(tls, v, int32(OP_NotExists), iDest, 0, regRowid)
|
|
_sqlite3RowidConstraint(tls, pParse, onError, pDest)
|
|
_sqlite3VdbeJumpHere(tls, v, addr2)
|
|
}
|
|
_autoIncStep(tls, pParse, regAutoinc, regRowid)
|
|
} else {
|
|
if (*TTable)(unsafe.Pointer(pDest)).FpIndex == uintptr(0) && !((*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&libc.Uint32FromInt32(DBFLAG_VacuumInto) != 0) {
|
|
addr1 = _sqlite3VdbeAddOp2(tls, v, int32(OP_NewRowid), iDest, regRowid)
|
|
} else {
|
|
addr1 = _sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), iSrc, regRowid)
|
|
}
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_Vacuum) != 0 {
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_SeekEnd), iDest)
|
|
insFlags = libc.Uint8FromInt32(libc.Int32FromInt32(OPFLAG_APPEND) | libc.Int32FromInt32(OPFLAG_USESEEKRESULT) | libc.Int32FromInt32(OPFLAG_PREFORMAT))
|
|
} else {
|
|
insFlags = libc.Uint8FromInt32(libc.Int32FromInt32(OPFLAG_NCHANGE) | libc.Int32FromInt32(OPFLAG_LASTROWID) | libc.Int32FromInt32(OPFLAG_APPEND) | libc.Int32FromInt32(OPFLAG_PREFORMAT))
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_Vacuum) == uint32(0) {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_RowData), iSrc, regData, int32(1))
|
|
insFlags = libc.Uint8FromInt32(int32(insFlags) & ^libc.Int32FromInt32(OPFLAG_PREFORMAT))
|
|
} else {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_RowCell), iDest, iSrc, regRowid)
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Insert), iDest, regData, regRowid)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_Vacuum) == uint32(0) {
|
|
_sqlite3VdbeChangeP4(tls, v, -int32(1), pDest, -int32(5))
|
|
}
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(insFlags))
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), iSrc, addr1)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Close), iSrc, 0)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Close), iDest, 0)
|
|
} else {
|
|
_sqlite3TableLock(tls, pParse, iDbDest, (*TTable)(unsafe.Pointer(pDest)).Ftnum, uint8(1), (*TTable)(unsafe.Pointer(pDest)).FzName)
|
|
_sqlite3TableLock(tls, pParse, iDbSrc, (*TTable)(unsafe.Pointer(pSrc)).Ftnum, uint8(0), (*TTable)(unsafe.Pointer(pSrc)).FzName)
|
|
}
|
|
pDestIdx = (*TTable)(unsafe.Pointer(pDest)).FpIndex
|
|
for {
|
|
if !(pDestIdx != 0) {
|
|
break
|
|
}
|
|
idxInsFlags = uint8(0)
|
|
pSrcIdx = (*TTable)(unsafe.Pointer(pSrc)).FpIndex
|
|
for {
|
|
if !(pSrcIdx != 0) {
|
|
break
|
|
}
|
|
if _xferCompatibleIndex(tls, pDestIdx, pSrcIdx) != 0 {
|
|
break
|
|
}
|
|
goto _9
|
|
_9:
|
|
;
|
|
pSrcIdx = (*TIndex)(unsafe.Pointer(pSrcIdx)).FpNext
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_OpenRead), iSrc, libc.Int32FromUint32((*TIndex)(unsafe.Pointer(pSrcIdx)).Ftnum), iDbSrc)
|
|
_sqlite3VdbeSetP4KeyInfo(tls, pParse, pSrcIdx)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_OpenWrite), iDest, libc.Int32FromUint32((*TIndex)(unsafe.Pointer(pDestIdx)).Ftnum), iDbDest)
|
|
_sqlite3VdbeSetP4KeyInfo(tls, pParse, pDestIdx)
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(OPFLAG_BULKCSR))
|
|
addr1 = _sqlite3VdbeAddOp2(tls, v, int32(OP_Rewind), iSrc, 0)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_Vacuum) != 0 {
|
|
/* This INSERT command is part of a VACUUM operation, which guarantees
|
|
** that the destination table is empty. If all indexed columns use
|
|
** collation sequence BINARY, then it can also be assumed that the
|
|
** index will be populated by inserting keys in strictly sorted
|
|
** order. In this case, instead of seeking within the b-tree as part
|
|
** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the
|
|
** OP_IdxInsert to seek to the point within the b-tree where each key
|
|
** should be inserted. This is faster.
|
|
**
|
|
** If any of the indexed columns use a collation sequence other than
|
|
** BINARY, this optimization is disabled. This is because the user
|
|
** might change the definition of a collation sequence and then run
|
|
** a VACUUM command. In that case keys may not be written in strictly
|
|
** sorted order. */
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pSrcIdx)).FnColumn)) {
|
|
break
|
|
}
|
|
zColl = **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pSrcIdx)).FazColl + uintptr(i)*8))
|
|
if Xsqlite3_stricmp(tls, uintptr(unsafe.Pointer(&_sqlite3StrBINARY)), zColl) != 0 {
|
|
break
|
|
}
|
|
goto _10
|
|
_10:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if i == libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pSrcIdx)).FnColumn) {
|
|
idxInsFlags = libc.Uint8FromInt32(libc.Int32FromInt32(OPFLAG_USESEEKRESULT) | libc.Int32FromInt32(OPFLAG_PREFORMAT))
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_SeekEnd), iDest)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_RowCell), iDest, iSrc)
|
|
}
|
|
} else {
|
|
if !((*TTable)(unsafe.Pointer(pSrc)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) && int32(uint32(*(*uint16)(unsafe.Pointer(pDestIdx + 100))&0x3>>0)) == int32(SQLITE_IDXTYPE_PRIMARYKEY) {
|
|
idxInsFlags = libc.Uint8FromInt32(int32(idxInsFlags) | libc.Int32FromInt32(OPFLAG_NCHANGE))
|
|
}
|
|
}
|
|
if libc.Int32FromUint8(idxInsFlags) != libc.Int32FromInt32(OPFLAG_USESEEKRESULT)|libc.Int32FromInt32(OPFLAG_PREFORMAT) {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_RowData), iSrc, regData, int32(1))
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_Vacuum) == uint32(0) && !((*TTable)(unsafe.Pointer(pDest)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) && int32(uint32(*(*uint16)(unsafe.Pointer(pDestIdx + 100))&0x3>>0)) == int32(SQLITE_IDXTYPE_PRIMARYKEY) {
|
|
_codeWithoutRowidPreupdate(tls, pParse, pDest, iDest, regData)
|
|
}
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IdxInsert), iDest, regData)
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(libc.Int32FromUint8(idxInsFlags)|int32(OPFLAG_APPEND)))
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), iSrc, addr1+int32(1))
|
|
_sqlite3VdbeJumpHere(tls, v, addr1)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Close), iSrc, 0)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Close), iDest, 0)
|
|
goto _8
|
|
_8:
|
|
;
|
|
pDestIdx = (*TIndex)(unsafe.Pointer(pDestIdx)).FpNext
|
|
}
|
|
if emptySrcTest != 0 {
|
|
_sqlite3VdbeJumpHere(tls, v, emptySrcTest)
|
|
}
|
|
_sqlite3ReleaseTempReg(tls, pParse, regRowid)
|
|
_sqlite3ReleaseTempReg(tls, pParse, regData)
|
|
if emptyDestTest != 0 {
|
|
_sqlite3AutoincrementEnd(tls, pParse)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Halt), SQLITE_OK, 0)
|
|
_sqlite3VdbeJumpHere(tls, v, emptyDestTest)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Close), iDest, 0)
|
|
return 0
|
|
} else {
|
|
return int32(1)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set up a raw page so that it looks like a database page holding
|
|
// ** no entries.
|
|
// */
|
|
func _zeroPage(tls *libc.TLS, pPage uintptr, flags int32) {
|
|
var data, pBt uintptr
|
|
var first, hdr, v1 int32
|
|
_, _, _, _, _ = data, first, hdr, pBt, v1
|
|
data = (*TMemPage)(unsafe.Pointer(pPage)).FaData
|
|
pBt = (*TMemPage)(unsafe.Pointer(pPage)).FpBt
|
|
hdr = libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset)
|
|
if libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_FAST_SECURE) != 0 {
|
|
libc.Xmemset(tls, data+uintptr(hdr), 0, uint64((*TBtShared)(unsafe.Pointer(pBt)).FusableSize-libc.Uint32FromInt32(hdr)))
|
|
}
|
|
**(**uint8)(__ccgo_up(data + uintptr(hdr))) = uint8(libc.Uint8FromInt32(flags))
|
|
if flags&int32(PTF_LEAF) == 0 {
|
|
v1 = int32(12)
|
|
} else {
|
|
v1 = int32(8)
|
|
}
|
|
first = hdr + v1
|
|
libc.Xmemset(tls, data+uintptr(hdr+int32(1)), 0, uint64(4))
|
|
**(**uint8)(__ccgo_up(data + uintptr(hdr+int32(7)))) = uint8(0)
|
|
**(**uint8)(__ccgo_up(data + uintptr(hdr+int32(5)))) = uint8((*TBtShared)(unsafe.Pointer(pBt)).FusableSize >> libc.Int32FromInt32(8))
|
|
**(**uint8)(__ccgo_up(data + uintptr(hdr+int32(5)) + 1)) = uint8((*TBtShared)(unsafe.Pointer(pBt)).FusableSize)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FnFree = libc.Int32FromUint16(uint16((*TBtShared)(unsafe.Pointer(pBt)).FusableSize - libc.Uint32FromInt32(first)))
|
|
_decodeFlags(tls, pPage, flags)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FcellOffset = libc.Uint16FromInt32(first)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FaDataEnd = data + uintptr((*TBtShared)(unsafe.Pointer(pBt)).FpageSize)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx = data + uintptr(first)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FaDataOfst = data + uintptr((*TMemPage)(unsafe.Pointer(pPage)).FchildPtrSize)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FnOverflow = uint8(0)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FmaskPage = uint16((*TBtShared)(unsafe.Pointer(pBt)).FpageSize - libc.Uint32FromInt32(1))
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FnCell = uint16(0)
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FisInit = uint8(1)
|
|
}
|