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>
4298 lines
178 KiB
Go
4298 lines
178 KiB
Go
// Code generated by modernc.org/undup from the per-target sqlite_*.go files; DO NOT EDIT.
|
|
|
|
//go:build (darwin && amd64) || (darwin && arm64) || (freebsd && amd64) || (linux && amd64) || (linux && loong64) || (netbsd && amd64) || (openbsd && amd64)
|
|
|
|
package sqlite3
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"modernc.org/libc"
|
|
)
|
|
|
|
// 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, libc.Uint8FromInt8((*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 int32((**(**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 int8) {
|
|
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
|
|
**(**int8)(__ccgo_up((*Tsqlite3_str)(unsafe.Pointer(p)).FzText + uintptr(v4))) = c
|
|
}
|
|
}
|
|
|
|
// 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 int8, enc Tu8) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if int32(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 int32(affinity) <= int32(SQLITE_AFF_REAL) {
|
|
_sqlite3VdbeIntegerAffinity(tls, pRec)
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if int32(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 {
|
|
**(**int8)(__ccgo_up(zAff + uintptr(j))) = int8(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 int32(_sqlite3CompareAffinity(tls, pRight, **(**int8)(__ccgo_up(zAff + uintptr(j))))) == int32(SQLITE_AFF_BLOB) {
|
|
**(**int8)(__ccgo_up(zAff + uintptr(j))) = int8(SQLITE_AFF_BLOB)
|
|
}
|
|
if _sqlite3ExprNeedsNoAffinityChange(tls, pRight, **(**int8)(__ccgo_up(zAff + uintptr(j)))) != 0 {
|
|
**(**int8)(__ccgo_up(zAff + uintptr(j))) = int8(SQLITE_AFF_BLOB)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
j = j + 1
|
|
}
|
|
**(**uintptr)(__ccgo_up(pzAff)) = zAff
|
|
return regBase
|
|
}
|
|
|
|
// 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 int8
|
|
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 = int8(SQLITE_AFF_INTEGER)
|
|
} else {
|
|
aff = _sqlite3ExprAffinity(tls, (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FaColExpr + 8 + uintptr(n)*32))).FpExpr)
|
|
}
|
|
}
|
|
if int32(aff) < int32(SQLITE_AFF_BLOB) {
|
|
aff = int8(SQLITE_AFF_BLOB)
|
|
}
|
|
if int32(aff) > int32(SQLITE_AFF_NUMERIC) {
|
|
aff = int8(SQLITE_AFF_NUMERIC)
|
|
}
|
|
**(**int8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FzColAff + uintptr(n))) = aff
|
|
goto _1
|
|
_1:
|
|
;
|
|
n = n + 1
|
|
}
|
|
**(**int8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FzColAff + uintptr(n))) = 0
|
|
return (*TIndex)(unsafe.Pointer(pIdx)).FzColAff
|
|
}
|
|
|
|
// 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 int32(_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 int32(_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
|
|
//
|
|
// /*
|
|
// ** 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 int8
|
|
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 {
|
|
**(**int8)(__ccgo_up(zRet + uintptr(i))) = _sqlite3CompareAffinity(tls, (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpEList + 8 + uintptr(i)*32))).FpExpr, a)
|
|
} else {
|
|
**(**int8)(__ccgo_up(zRet + uintptr(i))) = a
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int8)(__ccgo_up(zRet + uintptr(nVal))) = int8('\000')
|
|
}
|
|
return zRet
|
|
}
|
|
|
|
// 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[libc.Uint8FromInt8(**(**int8)(__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), int8(','))
|
|
} 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
|
|
**(**int8)(__ccgo_up(v1)) = _hexdigits[libc.Int32FromUint8(c)>>int32(4)&int32(0xf)]
|
|
v1 = z
|
|
z = z + 1
|
|
**(**int8)(__ccgo_up(v1)) = _hexdigits[libc.Int32FromUint8(c)&int32(0xf)]
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
pBlob = pBlob + 1
|
|
}
|
|
**(**int8)(__ccgo_up(z)) = 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, libc.Int8FromUint8(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
|
|
//
|
|
// /*
|
|
// ** 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))
|
|
**(**int8)(__ccgo_up(zNew + uintptr(cnt))) = 0
|
|
v3 = libc.Int32FromInt32(0)
|
|
iTo = v3
|
|
iFrom = v3
|
|
for {
|
|
if !(iFrom < cnt) {
|
|
break
|
|
}
|
|
if int32(**(**int8)(__ccgo_up(zNew + uintptr(iFrom)))) == libc.Int32FromUint8((**(**[4]Tu8)(__ccgo_up(bp)))[int32(3)]) {
|
|
iFrom = iFrom + 1
|
|
}
|
|
v3 = iTo
|
|
iTo = iTo + 1
|
|
**(**int8)(__ccgo_up(zNew + uintptr(v3))) = **(**int8)(__ccgo_up(zNew + uintptr(iFrom)))
|
|
goto _2
|
|
_2:
|
|
;
|
|
iFrom = iFrom + 1
|
|
}
|
|
**(**int8)(__ccgo_up(zNew + uintptr(iTo))) = 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) || int32(_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) && int32(**(**int8)(__ccgo_up(zNew))) == int32('-') {
|
|
isNum = +libc.Int32FromInt32(1)
|
|
} else {
|
|
**(**int8)(__ccgo_up(zNew + uintptr(iTo-int32(1)))) = **(**int8)(__ccgo_up(zNew + uintptr(iTo-int32(1)))) + 1
|
|
isNum = _sqlite3AtoF(tls, zNew, bp+16)
|
|
**(**int8)(__ccgo_up(zNew + uintptr(iTo-int32(1)))) = **(**int8)(__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 && **(**int8)(__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
|
|
}
|
|
|
|
// 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 int32(**(**int8)(__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 int32(**(**int8)(__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 int8
|
|
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 int32(**(**int8)(__ccgo_up(z + uintptr(n)))) == int32('[') || int32(**(**int8)(__ccgo_up(z + uintptr(n)))) == int32('.') {
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
cSaved = **(**int8)(__ccgo_up(z + uintptr(n)))
|
|
**(**int8)(__ccgo_up(z + uintptr(n))) = 0
|
|
x = _jsonLookupStep(tls, p+192, uint32(0), z+uintptr(1), uint32(0))
|
|
**(**int8)(__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
|
|
//
|
|
// /* 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 int32(**(**int8)(__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 int32(**(**int8)(__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 int32(**(**int8)(__ccgo_up(zPath))) != int32('$') {
|
|
goto json_remove_patherror
|
|
}
|
|
if int32(**(**int8)(__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 int32(**(**int8)(__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
|
|
//
|
|
// /*
|
|
// ** 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 int8
|
|
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.Int8FromInt32(0)
|
|
**(**int8)(__ccgo_up(zFree + 3)) = v3
|
|
v2 = v3
|
|
**(**int8)(__ccgo_up(zFree + 2)) = v2
|
|
v1 = v2
|
|
**(**int8)(__ccgo_up(zFree + 1)) = v1
|
|
**(**int8)(__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
|
|
}
|
|
**(**int8)(__ccgo_up(zSuperJournal + uintptr(**(**Ti64)(__ccgo_up(bp))))) = 0
|
|
**(**int8)(__ccgo_up(zSuperJournal + uintptr(**(**Ti64)(__ccgo_up(bp))+int64(1)))) = 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]int8
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = 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]int8)(__ccgo_up(bp + 18)))[0] = libc.Int8FromUint32(c & libc.Uint32FromInt32(^(libc.Int32FromUint8(_sqlite3CtypeMap[uint8(c)]) & libc.Int32FromInt32(0x20))))
|
|
(**(**[3]int8)(__ccgo_up(bp + 18)))[int32(1)] = libc.Int8FromUint8(_sqlite3UpperToLower[uint8(c)])
|
|
(**(**[3]int8)(__ccgo_up(bp + 18)))[int32(2)] = 0
|
|
} else {
|
|
(**(**[3]int8)(__ccgo_up(bp + 18)))[0] = libc.Int8FromUint32(c)
|
|
(**(**[3]int8)(__ccgo_up(bp + 18)))[int32(1)] = 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 int32(_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 && int32(_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)
|
|
}
|
|
|
|
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 || int32(**(**int8)(__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
|
|
//
|
|
// /*
|
|
// ** 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)) - libc.Uint32FromInt8(**(**int8)(__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
|
|
//
|
|
// /*
|
|
// ** 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 int32(**(**int8)(__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
|
|
//
|
|
// /*
|
|
// ** 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[libc.Uint8FromInt8(**(**int8)(__ccgo_up(zStart)))])&int32(0x01) != 0) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
zStart = zStart + 1
|
|
}
|
|
for libc.Int32FromUint8(_sqlite3CtypeMap[libc.Uint8FromInt8(**(**int8)(__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, libc.Uint8FromInt8((*TColumn)(unsafe.Pointer(pCol)).Faffinity), bp)
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
_sqlite3VdbeAppendP4(tls, v, **(**uintptr)(__ccgo_up(bp)), -int32(11))
|
|
}
|
|
}
|
|
if int32((*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[libc.Uint8FromInt8(**(**int8)(__ccgo_up(zStart)))])&int32(0x01) != 0 {
|
|
zStart = zStart + 1
|
|
}
|
|
n = int32(int64(zEnd) - int64(zStart))
|
|
for libc.Int32FromUint8(_sqlite3CtypeMap[libc.Uint8FromInt8(**(**int8)(__ccgo_up(zStart + uintptr(n-int32(1)))))])&int32(0x01) != 0 {
|
|
n = n - 1
|
|
}
|
|
return _sqlite3DbStrNDup(tls, db, zStart, libc.Uint64FromInt32(n))
|
|
}
|
|
|
|
// 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[libc.Uint8FromInt8(**(**int8)(__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[libc.Uint8FromInt8(**(**int8)(__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 int8) {
|
|
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) && int32((*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
|
|
//
|
|
// /*
|
|
// ** 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 int32((*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, libc.Uint16FromInt8(**(**int8)(__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(int32(**(**int8)(__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) && int32((*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 = int32(_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 int32(**(**int8)(__ccgo_up(z))) != int32('i') && int32(**(**int8)(__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
|
|
//
|
|
// /*
|
|
// ** 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]int8
|
|
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] = int8('_')
|
|
aSpec[int32(1)] = int8('%')
|
|
aSpec[int32(2)] = 0
|
|
} else {
|
|
aSpec[0] = int8('*')
|
|
aSpec[int32(1)] = int8('?')
|
|
aSpec[int32(2)] = int8('[')
|
|
}
|
|
for int64(i) <= nText {
|
|
if int64(i) == nText || int32(**(**int8)(__ccgo_up(zText + uintptr(i)))) == int32(aSpec[0]) || int32(**(**int8)(__ccgo_up(zText + uintptr(i)))) == int32(aSpec[int32(1)]) || int32(**(**int8)(__ccgo_up(zText + uintptr(i)))) == int32(aSpec[int32(2)]) {
|
|
if _fts5ExprCountChar(tls, zText+uintptr(iFirst), i-iFirst) >= int32(3) {
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**int8)(__ccgo_up(zExpr + uintptr(v1))) = int8('"')
|
|
jj = iFirst
|
|
for {
|
|
if !(jj < i) {
|
|
break
|
|
}
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**int8)(__ccgo_up(zExpr + uintptr(v1))) = **(**int8)(__ccgo_up(zText + uintptr(jj)))
|
|
if int32(**(**int8)(__ccgo_up(zText + uintptr(jj)))) == int32('"') {
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**int8)(__ccgo_up(zExpr + uintptr(v1))) = int8('"')
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
jj = jj + 1
|
|
}
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**int8)(__ccgo_up(zExpr + uintptr(v1))) = int8('"')
|
|
v1 = iOut
|
|
iOut = iOut + 1
|
|
**(**int8)(__ccgo_up(zExpr + uintptr(v1))) = int8(' ')
|
|
}
|
|
if int32(**(**int8)(__ccgo_up(zText + uintptr(i)))) == int32(aSpec[int32(2)]) {
|
|
i = i + int32(2)
|
|
if int32(**(**int8)(__ccgo_up(zText + uintptr(i-int32(1))))) == int32('^') {
|
|
i = i + 1
|
|
}
|
|
for int64(i) < nText && int32(**(**int8)(__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
|
|
}
|
|
}
|
|
**(**int8)(__ccgo_up(zExpr + uintptr(iOut))) = int8('\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
|
|
//
|
|
// /*
|
|
// ** 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 int32(**(**int8)(__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 && int32(**(**int8)(__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
|
|
//
|
|
// /*
|
|
// ** 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 = libc.Uint8FromInt8(_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
|
|
**(**int8)(__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 && int32(**(**int8)(__ccgo_up(zColAff + uintptr(j)))) <= int32(SQLITE_AFF_BLOB) {
|
|
v2 = j
|
|
j = j - 1
|
|
**(**int8)(__ccgo_up(zColAff + uintptr(v2))) = 0
|
|
}
|
|
}
|
|
return zColAff
|
|
}
|
|
|
|
// 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 && int32(**(**int8)(__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]int8
|
|
_ = 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
|
|
//
|
|
// /*
|
|
// ** 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)) {
|
|
**(**int8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn))) = 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) {
|
|
**(**int8)(__ccgo_up((*TMem)(unsafe.Pointer(pMem)).Fz + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn))) = 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 && int32(**(**int8)(__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
|
|
//
|
|
// /*
|
|
// ** 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 int8
|
|
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
|
|
//
|
|
// /*
|
|
// ** 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
|
|
}
|
|
**(**int8)(__ccgo_up(pBuf + uintptr(len1))) = 0
|
|
**(**int8)(__ccgo_up(pBuf + uintptr(len1+int32(1)))) = 0
|
|
**(**int8)(__ccgo_up(pBuf + uintptr(len1+int32(2)))) = 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) {
|
|
**(**int8)(__ccgo_up((*TMem)(unsafe.Pointer(pDest)).Fz + uintptr(len1))) = 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
|
|
//
|
|
// /*
|
|
// ** 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 = libc.Uint8FromInt8(**(**int8)(__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 = libc.Uint8FromInt8((**(**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 = libc.Uint8FromInt8(_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 int8
|
|
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 = 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 int32(aff) != int32(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
|
|
//
|
|
// /*
|
|
// ** 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, libc.Uint8FromInt8((*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 !(**(**int8)(__ccgo_up(zSuper + uintptr(nSuper))) != 0) {
|
|
break
|
|
}
|
|
cksum = cksum + libc.Uint32FromInt8(**(**int8)(__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 int32((*TColumn)(unsafe.Pointer(pDestCol)).Faffinity) != int32((*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
|
|
}
|