view release on metacpan or search on metacpan
void
disconnect(dbh)
SV * dbh
CODE:
D_imp_dbh(dbh);
if ( !DBIc_ACTIVE(imp_dbh) ) {
XSRETURN_YES;
}
/* Check for disconnect() being called whilst refs to cursors */
/* still exists. This possibly needs some more thought. */
if (DBIc_ACTIVE_KIDS(imp_dbh) && DBIc_WARN(imp_dbh) && !dirty) {
STRLEN lna;
char *plural = (DBIc_ACTIVE_KIDS(imp_dbh)==1) ? "" : "s";
warn("%s->disconnect invalidates %d active statement handle%s %s",
SvPV(dbh,lna), (int)DBIc_ACTIVE_KIDS(imp_dbh), plural,
"(either destroy statement handles or call finish on them before disconnecting)");
}
ST(0) = dbd_db_disconnect(dbh, imp_dbh) ? &sv_yes : &sv_no;
DBIc_ACTIVE_off(imp_dbh); /* ensure it's off, regardless */
sqlite-amalgamation.c view on Meta::CPAN
**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
*/
/*
** Structures used by the virtual table interface
*/
typedef struct sqlite3_vtab sqlite3_vtab;
typedef struct sqlite3_index_info sqlite3_index_info;
typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
typedef struct sqlite3_module sqlite3_module;
/*
** CAPI3REF: Virtual Table Object {H18000} <S20400>
** KEYWORDS: sqlite3_module
** EXPERIMENTAL
**
** A module is a class of virtual tables. Each module is defined
** by an instance of the following structure. This structure consists
** mostly of methods for the module.
sqlite-amalgamation.c view on Meta::CPAN
int iVersion;
int (*xCreate)(sqlite3*, void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVTab, char**);
int (*xConnect)(sqlite3*, void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVTab, char**);
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
int (*xDisconnect)(sqlite3_vtab *pVTab);
int (*xDestroy)(sqlite3_vtab *pVTab);
int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
int (*xClose)(sqlite3_vtab_cursor*);
int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
int argc, sqlite3_value **argv);
int (*xNext)(sqlite3_vtab_cursor*);
int (*xEof)(sqlite3_vtab_cursor*);
int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);
int (*xBegin)(sqlite3_vtab *pVTab);
int (*xSync)(sqlite3_vtab *pVTab);
int (*xCommit)(sqlite3_vtab *pVTab);
int (*xRollback)(sqlite3_vtab *pVTab);
int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
};
sqlite-amalgamation.c view on Meta::CPAN
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
int nRef; /* Used internally */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
/*
** CAPI3REF: Virtual Table Cursor Object {H18020} <S20400>
** KEYWORDS: sqlite3_vtab_cursor
** EXPERIMENTAL
**
** Every module implementation uses a subclass of the following structure
** to describe cursors that point into the virtual table and are used
** to loop through the virtual table. Cursors are created using the
** xOpen method of the module. Each module implementation will define
** the content of a cursor structure to suit its own needs.
**
** This superclass exists in order to define fields of the cursor that
** are common to all implementations.
**
** This interface is experimental and is subject to change or
** removal in future releases of SQLite.
*/
struct sqlite3_vtab_cursor {
sqlite3_vtab *pVtab; /* Virtual table of this cursor */
/* Virtual table implementations will typically add additional fields */
};
/*
** CAPI3REF: Declare The Schema Of A Virtual Table {H18280} <S20400>
** EXPERIMENTAL
**
** The xCreate and xConnect methods of a module use the following API
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
sqlite-amalgamation.c view on Meta::CPAN
SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);
struct UnpackedRecord; /* Forward declaration. Definition in vdbeaux.c. */
SQLITE_PRIVATE int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
int iTable, /* Index of root page */
int wrFlag, /* 1 for writing. 0 for read-only */
struct KeyInfo*, /* First argument to compare function */
BtCursor *pCursor /* Space to write cursor structure */
);
SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreeMoveto(
BtCursor*,
const void *pKey,
struct UnpackedRecord *pUnKey,
i64 nKey,
int bias,
sqlite-amalgamation.c view on Meta::CPAN
** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of
** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid
** is generated for each row of the table. Table.hasPrimKey is true if
** the table has any PRIMARY KEY, INTEGER or otherwise.
**
** Table.tnum is the page number for the root BTree page of the table in the
** database file. If Table.iDb is the index of the database table backend
** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that
** holds temporary tables and indices. If Table.isEphem
** is true, then the table is stored in a file that is automatically deleted
** when the VDBE cursor to the table is closed. In this case Table.tnum
** refers VDBE cursor number that holds the table open, not to the root
** page number. Transient tables are used to hold the results of a
** sub-query that appears instead of a real table name in the FROM clause
** of a SELECT statement.
*/
struct Table {
sqlite3 *db; /* Associated database connection. Might be NULL. */
char *zName; /* Name of the table */
int nCol; /* Number of columns in this table */
Column *aCol; /* Information about each column */
int iPKey; /* If not less then 0, use aCol[iPKey] as the primary key */
sqlite-amalgamation.c view on Meta::CPAN
** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list
** of argument if the expression is a function.
**
** Expr.token is the operator token for this node. For some expressions
** that have subexpressions, Expr.token can be the complete text that gave
** rise to the Expr. In the latter case, the token is marked as being
** a compound token.
**
** An expression of the form ID or ID.ID refers to a column in a table.
** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
** the integer cursor number of a VDBE cursor pointing to that table and
** Expr.iColumn is the column number for the specific column. If the
** expression is used as a result in an aggregate SELECT, then the
** value is also stored in the Expr.iAgg column in the aggregate so that
** it can be accessed after all aggregates are computed.
**
** If the expression is a function, the Expr.iTable is an integer code
** representing which function. If the expression is an unbound variable
** marker (a question mark character '?' in the original SQL) then the
** Expr.iTable holds the index number for that variable.
**
sqlite-amalgamation.c view on Meta::CPAN
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
i16 nAlloc; /* Number of entries allocated in a[] below */
struct SrcList_item {
char *zDatabase; /* Name of database holding this table */
char *zName; /* Name of the table */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* An SQL table corresponding to zName */
Select *pSelect; /* A SELECT statement used in place of a table name */
u8 isPopulated; /* Temporary table associated with SELECT is populated */
u8 jointype; /* Type of join between this able and the previous */
int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */
} a[1]; /* One entry for each identifier on the list */
};
/*
** Permitted values of the SrcList.a.jointype field
*/
#define JT_INNER 0x0001 /* Any kind of inner or cross join */
sqlite-amalgamation.c view on Meta::CPAN
** either NULL or a copy of some pIdxInfo. So for cleanup it is
** sufficient to free all of the pIdxInfo pointers.
**
*/
struct WhereLevel {
int iFrom; /* Which entry in the FROM clause */
int flags; /* Flags associated with this level */
int iMem; /* First memory cell used by this level */
int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */
Index *pIdx; /* Index used. NULL if no index */
int iTabCur; /* The VDBE cursor used to access the table */
int iIdxCur; /* The VDBE cursor used to acesss pIdx */
int brk; /* Jump here to break out of the loop */
int nxt; /* Jump here to start the next IN combination */
int cont; /* Jump here to continue with the next loop cycle */
int top; /* First instruction of interior of the loop */
int op, p1, p2; /* Opcode used to terminate the loop */
int nEq; /* Number of == or IN constraints on this loop */
int nIn; /* Number of IN operators constraining this loop */
struct InLoop {
int iCur; /* The VDBE cursor used by this IN operator */
int topAddr; /* Top of the IN loop */
} *aInLoop; /* Information about each nested IN operator */
sqlite3_index_info *pBestIdx; /* Index information for this level */
/* The following field is really not part of the current level. But
** we need a place to cache index information for each table in the
** FROM clause and the WhereLevel structure is a convenient place.
*/
sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */
};
sqlite-amalgamation.c view on Meta::CPAN
u8 nameClash; /* A permanent table name clashes with temp table name */
u8 checkSchema; /* Causes schema cookie check after an error */
u8 nested; /* Number of nested calls to the parser/code generator */
u8 parseError; /* True after a parsing error. Ticket #1794 */
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
u8 nTempInUse; /* Number of aTempReg[] currently checked out */
int aTempReg[8]; /* Holding area for temporary registers */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
int nSet; /* Number of sets used so far */
int ckBase; /* Base register of data during check constraints */
int disableColCache; /* True to disable adding to column cache */
int nColCache; /* Number of entries in the column cache */
int iColCache; /* Next entry of the cache to replace */
struct yColCache {
int iTable; /* Table cursor number */
int iColumn; /* Table column number */
char affChange; /* True if this register has had an affinity change */
int iReg; /* Register holding value of this column */
} aColCache[10]; /* One for each valid column cache entry */
u32 writeMask; /* Start a write transaction on these databases */
u32 cookieMask; /* Bitmask of schema verified databases */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
sqlite-amalgamation.c view on Meta::CPAN
TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
};
/*
* An instance of struct TriggerStack stores information required during code
* generation of a single trigger program. While the trigger program is being
* coded, its associated TriggerStack instance is pointed to by the
* "pTriggerStack" member of the Parse structure.
*
* The pTab member points to the table that triggers are being coded on. The
* newIdx member contains the index of the vdbe cursor that points at the temp
* table that stores the new.* references. If new.* references are not valid
* for the trigger being coded (for example an ON DELETE trigger), then newIdx
* is set to -1. The oldIdx member is analogous to newIdx, for old.* references.
*
* The ON CONFLICT policy to be used for the trigger program steps is stored
* as the orconf member. If this is OE_Default, then the ON CONFLICT clause
* specified for individual triggers steps is used.
*
* struct TriggerStack has a "pNext" member, to allow linked lists to be
* constructed. When coding nested triggers (triggers fired by other triggers)
sqlite-amalgamation.c view on Meta::CPAN
* pointer. Once the nested trigger has been coded, the pNext value is restored
* to the pTriggerStack member of the Parse stucture and coding of the parent
* trigger continues.
*
* Before a nested trigger is coded, the linked list pointed to by the
* pTriggerStack is scanned to ensure that the trigger is not about to be coded
* recursively. If this condition is detected, the nested trigger is not coded.
*/
struct TriggerStack {
Table *pTab; /* Table that triggers are currently being coded on */
int newIdx; /* Index of vdbe cursor to "new" temp table */
int oldIdx; /* Index of vdbe cursor to "old" temp table */
u32 newColMask;
u32 oldColMask;
int orconf; /* Current orconf policy */
int ignoreJump; /* where to jump to for a RAISE(IGNORE) */
Trigger *pTrigger; /* The trigger currently being coded */
TriggerStack *pNext; /* Next trigger down on the trigger stack */
};
/*
** The following structure contains information used by the sqliteFix...
sqlite-amalgamation.c view on Meta::CPAN
** of the following structure.
*/
typedef struct VdbeOp Op;
/*
** Boolean values
*/
typedef unsigned char Bool;
/*
** A cursor is a pointer into a single BTree within a database file.
** The cursor can seek to a BTree entry with a particular key, or
** loop over all entries of the Btree. You can also insert new BTree
** entries or retrieve the key or data from the entry that the cursor
** is currently pointing to.
**
** Every cursor that the virtual machine has open is represented by an
** instance of the following structure.
**
** If the Cursor.isTriggerRow flag is set it means that this cursor is
** really a single row that represents the NEW or OLD pseudo-table of
** a row trigger. The data for the row is stored in Cursor.pData and
** the rowid is in Cursor.iKey.
*/
struct Cursor {
BtCursor *pCursor; /* The cursor structure of the backend */
int iDb; /* Index of cursor database in db->aDb[] (or -1) */
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
i64 nextRowid; /* Next rowid returned by OP_NewRowid */
Bool zeroed; /* True if zeroed out and ready for reuse */
Bool rowidIsValid; /* True if lastRowid is valid */
Bool atFirst; /* True if pointing to first entry */
Bool useRandomRowid; /* Generate new record numbers semi-randomly */
Bool nullRow; /* True if pointing to a row with no data */
Bool nextRowidValid; /* True if the nextRowid field is valid */
Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */
Bool ephemPseudoTable;
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
Bool isTable; /* True if a table requiring integer keys */
Bool isIndex; /* True if an index containing keys only - no data */
u8 bogusIncrKey; /* Something for pIncrKey to point to if pKeyInfo==0 */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
Btree *pBt; /* Separate file holding temporary table */
int nData; /* Number of bytes in pData */
char *pData; /* Data for a NEW or OLD pseudo-table */
i64 iKey; /* Key for the NEW or OLD pseudo-table row */
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
int nField; /* Number of fields in the header */
i64 seqCount; /* Sequence counter */
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
/* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheValid is true.
** aRow might point to (ephemeral) data for the current row, or it might
** be NULL.
*/
int cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
int payloadSize; /* Total number of bytes in the record */
u32 *aType; /* Type values for all entries in the record */
u32 *aOffset; /* Cached offsets to the start of each columns data */
u8 *aRow; /* Data for the current row, if all on one page */
};
typedef struct Cursor Cursor;
sqlite-amalgamation.c view on Meta::CPAN
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
Op *aOp; /* Space to hold the virtual machine's program */
int nLabel; /* Number of labels used */
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
int *aLabel; /* Space to hold the labels */
Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */
int nCursor; /* Number of slots in apCsr[] */
Cursor **apCsr; /* One element of this array for each open cursor */
int nVar; /* Number of entries in aVar[] */
Mem *aVar; /* Values for the OP_Variable opcode. */
char **azVar; /* Name of variables */
int okVar; /* True if azVar[] has been initialized */
int magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
int nCallback; /* Number of callbacks invoked so far */
int cacheCtr; /* Cursor row cache generation counter */
Fifo sFifo; /* A list of ROWIDs */
sqlite-amalgamation.c view on Meta::CPAN
** this structure.
**
** For some database files, the same underlying database cache might be
** shared between multiple connections. In that case, each contection
** has it own pointer to this object. But each instance of this object
** points to the same BtShared object. The database cache and the
** schema associated with the database file are all contained within
** the BtShared object.
**
** All fields in this structure are accessed under sqlite3.mutex.
** The pBt pointer itself may not be changed while there exists cursors
** in the referenced BtShared that point back to this Btree since those
** cursors have to do go through this Btree to find their BtShared and
** they often do so without holding sqlite3.mutex.
*/
struct Btree {
sqlite3 *db; /* The database connection holding this btree */
BtShared *pBt; /* Sharable content of this btree */
u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
u8 sharable; /* True if we can share pBt with another db */
u8 locked; /* True if db currently has pBt locked */
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
Btree *pNext; /* List of other sharable Btrees from the same db */
sqlite-amalgamation.c view on Meta::CPAN
** Fields in this structure are accessed under the BtShared.mutex
** mutex, except for nRef and pNext which are accessed under the
** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
** may not be modified once it is initially set as long as nRef>0.
** The pSchema field may be set once under BtShared.mutex and
** thereafter is unchanged as long as nRef>0.
*/
struct BtShared {
Pager *pPager; /* The page cache */
sqlite3 *db; /* Database connection currently using this Btree */
BtCursor *pCursor; /* A list of all open cursors */
MemPage *pPage1; /* First page of the database */
u8 inStmt; /* True if we are in a statement subtransaction */
u8 readOnly; /* True if the underlying file is readonly */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */
Pgno nTrunc; /* Non-zero if the db will be truncated (incr vacuum) */
#endif
u16 pageSize; /* Total number of bytes on a page */
sqlite-amalgamation.c view on Meta::CPAN
i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
u32 nData; /* Number of bytes of data */
u32 nPayload; /* Total amount of payload */
u16 nHeader; /* Size of the cell content header in bytes */
u16 nLocal; /* Amount of payload held locally */
u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
u16 nSize; /* Size of the cell content on the main b-tree page */
};
/*
** A cursor is a pointer to a particular entry within a particular
** b-tree within a database file.
**
** The entry is identified by its MemPage and the index in
** MemPage.aCell[] of the entry.
**
** When a single database file can shared by two more database connections,
** but cursors cannot be shared. Each cursor is associated with a
** particular database connection identified BtCursor.pBtree.db.
**
** Fields in this structure are accessed under the BtShared.mutex
** found at self->pBt->mutex.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
Pgno pgnoRoot; /* The root page of this tree */
MemPage *pPage; /* Page that contains the entry */
int idx; /* Index of the entry in pPage->aCell[] */
CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */
u8 atLast; /* Cursor pointing to the last entry */
u8 validNKey; /* True if info.nKey is valid */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
#ifndef SQLITE_OMIT_INCRBLOB
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
Pgno *aOverflow; /* Cache of overflow page locations */
#endif
};
/*
** Potential values for BtCursor.eState.
**
** CURSOR_VALID:
** Cursor points to a valid entry. getPayload() etc. may be called.
**
** CURSOR_INVALID:
** Cursor does not point to a valid entry. This can happen (for example)
** because the table is empty or because BtreeCursorFirst() has not been
** called.
**
** CURSOR_REQUIRESEEK:
** The table that this cursor was opened on still exists, but has been
** modified since the cursor was last used. The cursor position is saved
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
** this state, restoreCursorPosition() can be called to attempt to
** seek the cursor to the saved position.
**
** CURSOR_FAULT:
** A unrecoverable error (an I/O error or a malloc failure) has occurred
** on a different connection that shares the BtShared cache with this
** cursor. The error has left the cache in an inconsistent state.
** Do nothing else with this cursor. Any attempt to use the cursor
** should return the error code stored in BtCursor.skip
*/
#define CURSOR_INVALID 0
#define CURSOR_VALID 1
#define CURSOR_REQUIRESEEK 2
#define CURSOR_FAULT 3
/* The database page the PENDING_BYTE occupies. This page is never used.
** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They
** should possibly be consolidated (presumably in pager.h).
sqlite-amalgamation.c view on Meta::CPAN
** in memory) then there is no pending byte.
*/
#ifdef SQLITE_OMIT_DISKIO
# define PENDING_BYTE_PAGE(pBt) 0x7fffffff
#else
# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
#endif
/*
** A linked list of the following structures is stored at BtShared.pLock.
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
** is opened on the table with root page BtShared.iTable. Locks are removed
** from this list when a transaction is committed or rolled back, or when
** a btree handle is closed.
*/
struct BtLock {
Btree *pBtree; /* Btree handle holding this lock */
Pgno iTable; /* Root page of table */
u8 eLock; /* READ_LOCK or WRITE_LOCK */
BtLock *pNext; /* Next in BtShared.pLock list */
};
sqlite-amalgamation.c view on Meta::CPAN
*/
SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){
return (p->sharable==0 ||
(p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex)));
}
#endif
#ifndef SQLITE_OMIT_INCRBLOB
/*
** Enter and leave a mutex on a Btree given a cursor owned by that
** Btree. These entry points are used by incremental I/O and can be
** omitted if that module is not used.
*/
SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
sqlite3BtreeEnter(pCur->pBtree);
}
SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
sqlite3BtreeLeave(pCur->pBtree);
}
#endif /* SQLITE_OMIT_INCRBLOB */
sqlite-amalgamation.c view on Meta::CPAN
/* This (along with lockTable()) is where the ReadUncommitted flag is
** dealt with. If the caller is querying for a read-lock and the flag is
** set, it is unconditionally granted - even if there are write-locks
** on the table. If a write-lock is requested, the ReadUncommitted flag
** is not considered.
**
** In function lockTable(), if a read-lock is demanded and the
** ReadUncommitted flag is set, no entry is added to the locks list
** (BtShared.pLock).
**
** To summarize: If the ReadUncommitted flag is set, then read cursors do
** not create or respect table locks. The locking procedure for a
** write-cursor does not change.
*/
if(
0==(p->db->flags&SQLITE_ReadUncommitted) ||
eLock==WRITE_LOCK ||
iTab==MASTER_ROOT
){
for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
if( pIter->pBtree!=p && pIter->iTable==iTab &&
(pIter->eLock!=eLock || eLock!=READ_LOCK) ){
return SQLITE_LOCKED;
sqlite-amalgamation.c view on Meta::CPAN
if( pBt->pExclusive==p ){
pBt->pExclusive = 0;
}
}
#endif /* SQLITE_OMIT_SHARED_CACHE */
static void releasePage(MemPage *pPage); /* Forward reference */
/*
** Verify that the cursor holds a mutex on the BtShared
*/
#ifndef NDEBUG
static int cursorHoldsMutex(BtCursor *p){
return sqlite3_mutex_held(p->pBt->mutex);
}
#endif
#ifndef SQLITE_OMIT_INCRBLOB
/*
** Invalidate the overflow page-list cache for cursor pCur, if any.
*/
static void invalidateOverflowCache(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
sqlite3_free(pCur->aOverflow);
pCur->aOverflow = 0;
}
/*
** Invalidate the overflow page-list cache for all cursors opened
** on the shared btree structure pBt.
*/
static void invalidateAllOverflowCache(BtShared *pBt){
BtCursor *p;
assert( sqlite3_mutex_held(pBt->mutex) );
for(p=pBt->pCursor; p; p=p->pNext){
invalidateOverflowCache(p);
}
}
#else
#define invalidateOverflowCache(x)
#define invalidateAllOverflowCache(x)
#endif
/*
** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
*/
static int saveCursorPosition(BtCursor *pCur){
int rc;
assert( CURSOR_VALID==pCur->eState );
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
/* If this is an intKey table, then the above call to BtreeKeySize()
** stores the integer key in pCur->nKey. In this case this value is
** all that is required. Otherwise, if pCur is not open on an intKey
** table, then malloc space for and store the pCur->nKey bytes of key
** data.
*/
if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
sqlite-amalgamation.c view on Meta::CPAN
releasePage(pCur->pPage);
pCur->pPage = 0;
pCur->eState = CURSOR_REQUIRESEEK;
}
invalidateOverflowCache(pCur);
return rc;
}
/*
** Save the positions of all cursors except pExcept open on the table
** with root-page iRoot. Usually, this is called just before cursor
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
*/
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
BtCursor *p;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pExcept==0 || pExcept->pBt==pBt );
for(p=pBt->pCursor; p; p=p->pNext){
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
p->eState==CURSOR_VALID ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
}
}
}
return SQLITE_OK;
}
/*
** Clear the current cursor position.
*/
static void clearCursorPosition(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
pCur->eState = CURSOR_INVALID;
}
/*
** Restore the cursor to the position it was in (or as close to as possible)
** when saveCursorPosition() was called. Note that this call deletes the
** saved position info stored by saveCursorPosition(), so there can be
** at most one effective restoreCursorPosition() call after each
** saveCursorPosition().
*/
SQLITE_PRIVATE int sqlite3BtreeRestoreCursorPosition(BtCursor *pCur){
int rc;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState>=CURSOR_REQUIRESEEK );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skip;
}
pCur->eState = CURSOR_INVALID;
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, 0, pCur->nKey, 0, &pCur->skip);
if( rc==SQLITE_OK ){
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
}
return rc;
}
#define restoreCursorPosition(p) \
(p->eState>=CURSOR_REQUIRESEEK ? \
sqlite3BtreeRestoreCursorPosition(p) : \
SQLITE_OK)
/*
** Determine whether or not a cursor has moved from the position it
** was last placed at. Cursor can move when the row they are pointing
** at is deleted out from under them.
**
** This routine returns an error code if something goes wrong. The
** integer *pHasMoved is set to one if the cursor has moved and 0 if not.
*/
SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
int rc;
rc = restoreCursorPosition(pCur);
if( rc ){
*pHasMoved = 1;
return rc;
}
if( pCur->eState!=CURSOR_VALID || pCur->skip!=0 ){
sqlite-amalgamation.c view on Meta::CPAN
/*
** Free the pBt->pTmpSpace allocation
*/
static void freeTempSpace(BtShared *pBt){
sqlite3PageFree( pBt->pTmpSpace);
pBt->pTmpSpace = 0;
}
/*
** Close an open database and invalidate all cursors.
*/
SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
BtShared *pBt = p->pBt;
BtCursor *pCur;
/* Close all cursors opened via this handle. */
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
pBt->db = p->db;
pCur = pBt->pCursor;
while( pCur ){
BtCursor *pTmp = pCur;
pCur = pCur->pNext;
if( pTmp->pBtree==p ){
sqlite3BtreeCloseCursor(pTmp);
}
sqlite-amalgamation.c view on Meta::CPAN
if( rc==SQLITE_OK ){
pRef->pBt->nTransaction--;
}
btreeIntegrity(pRef);
}
return rc;
}
/*
** If there are no outstanding cursors and we are not in the middle
** of a transaction but there is a read lock on the database, then
** this routine unrefs the first page of the database file which
** has the effect of releasing the read lock.
**
** If there are any outstanding cursors, this routine is a no-op.
**
** If there is a transaction in progress, this routine is a no-op.
*/
static void unlockBtreeIfUnused(BtShared *pBt){
assert( sqlite3_mutex_held(pBt->mutex) );
if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
if( sqlite3PagerRefcount(pBt->pPager)>=1 ){
assert( pBt->pPage1->aData );
#if 0
if( pBt->pPage1->aData==0 ){
sqlite-amalgamation.c view on Meta::CPAN
**
** This routine implements the second phase of a 2-phase commit. The
** sqlite3BtreeSync() routine does the first phase and should be invoked
** prior to calling this routine. The sqlite3BtreeSync() routine did
** all the work of writing information out to disk and flushing the
** contents so that they are written onto the disk platter. All this
** routine has to do is delete or truncate the rollback journal
** (which causes the transaction to commit) and drop locks.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p){
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
pBt->db = p->db;
btreeIntegrity(p);
/* If the handle has a write-transaction open, commit the shared-btrees
** transaction and set the shared state to TRANS_READ.
sqlite-amalgamation.c view on Meta::CPAN
rc = sqlite3BtreeCommitPhaseOne(p, 0);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeCommitPhaseTwo(p);
}
sqlite3BtreeLeave(p);
return rc;
}
#ifndef NDEBUG
/*
** Return the number of write-cursors open on this handle. This is for use
** in assert() expressions, so it is only compiled if NDEBUG is not
** defined.
**
** For the purposes of this routine, a write-cursor is any cursor that
** is capable of writing to the databse. That means the cursor was
** originally opened for writing and the cursor has not be disabled
** by having its state changed to CURSOR_FAULT.
*/
static int countWriteCursors(BtShared *pBt){
BtCursor *pCur;
int r = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++;
}
return r;
}
#endif
/*
** This routine sets the state to CURSOR_FAULT and the error
** code to errCode for every cursor on BtShared that pBtree
** references.
**
** Every cursor is tripped, including cursors that belong
** to other database connections that happen to be sharing
** the cache with pBtree.
**
** This routine gets called when a rollback occurs.
** All cursors using the same cache must be tripped
** to prevent them from trying to use the btree after
** the rollback. The rollback may have deleted tables
** or moved root pages, so it is not sufficient to
** save the state of the cursor. The cursor must be
** invalidated.
*/
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
BtCursor *p;
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
clearCursorPosition(p);
p->eState = CURSOR_FAULT;
p->skip = errCode;
}
sqlite3BtreeLeave(pBtree);
}
/*
** Rollback the transaction in progress. All cursors will be
** invalided by this operation. Any attempt to use a cursor
** that was open at the beginning of this operation will result
** in an error.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p){
int rc;
BtShared *pBt = p->pBt;
MemPage *pPage1;
sqlite3BtreeEnter(p);
pBt->db = p->db;
rc = saveAllCursors(pBt, 0, 0);
#ifndef SQLITE_OMIT_SHARED_CACHE
if( rc!=SQLITE_OK ){
/* This is a horrible situation. An IO or malloc() error occured whilst
** trying to save cursor positions. If this is an automatic rollback (as
** the result of a constraint, malloc() failure or IO error) then
** the cache may be internally inconsistent (not contain valid trees) so
** we cannot simply return the error to the caller. Instead, abort
** all queries that may be using any of the cursors that failed to save.
*/
sqlite3BtreeTripAllCursors(p, rc);
}
#endif
btreeIntegrity(p);
unlockAllTables(p);
if( p->inTrans==TRANS_WRITE ){
int rc2;
sqlite-amalgamation.c view on Meta::CPAN
}
pBt->inStmt = 0;
sqlite3BtreeLeave(p);
return rc;
}
/*
** Rollback the active statement subtransaction. If no subtransaction
** is active this routine is a no-op.
**
** All cursors will be invalidated by this operation. Any attempt
** to use a cursor that was open at the beginning of this operation
** will result in an error.
*/
SQLITE_PRIVATE int sqlite3BtreeRollbackStmt(Btree *p){
int rc = SQLITE_OK;
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
pBt->db = p->db;
if( pBt->inStmt && !pBt->readOnly ){
rc = sqlite3PagerStmtRollback(pBt->pPager);
pBt->inStmt = 0;
}
sqlite3BtreeLeave(p);
return rc;
}
/*
** Create a new cursor for the BTree whose root is on the page
** iTable. The act of acquiring a cursor gets a read lock on
** the database file.
**
** If wrFlag==0, then the cursor can only be used for reading.
** If wrFlag==1, then the cursor can be used for reading or for
** writing if other conditions for writing are also met. These
** are the conditions that must be met in order for writing to
** be allowed:
**
** 1: The cursor must have been opened with wrFlag==1
**
** 2: Other database connections that share the same pager cache
** but which are not in the READ_UNCOMMITTED state may not have
** cursors open with wrFlag==0 on the same table. Otherwise
** the changes made by this write cursor would be visible to
** the read cursors in the other database connection.
**
** 3: The database must be writable (not on read-only media)
**
** 4: There must be an active transaction.
**
** No checking is done to make sure that page iTable really is the
** root page of a b-tree. If it is not, then the cursor acquired
** will not work correctly.
*/
static int btreeCursor(
Btree *p, /* The btree */
int iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
BtCursor *pCur /* Space for new cursor */
){
int rc;
BtShared *pBt = p->pBt;
assert( sqlite3BtreeHoldsMutex(p) );
if( wrFlag ){
if( pBt->readOnly ){
return SQLITE_READONLY;
}
if( checkReadLocks(p, iTable, 0, 0) ){
sqlite-amalgamation.c view on Meta::CPAN
if( rc!=SQLITE_OK ){
return rc;
}
if( pBt->readOnly && wrFlag ){
return SQLITE_READONLY;
}
}
pCur->pgnoRoot = (Pgno)iTable;
if( iTable==1 && pagerPagecount(pBt->pPager)==0 ){
rc = SQLITE_EMPTY;
goto create_cursor_exception;
}
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->pPage, 0);
if( rc!=SQLITE_OK ){
goto create_cursor_exception;
}
/* Now that no other errors can occur, finish filling in the BtCursor
** variables, link the cursor into the BtShared list and set *ppCur (the
** output argument to this function).
*/
pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p;
pCur->pBt = pBt;
pCur->wrFlag = wrFlag;
pCur->pNext = pBt->pCursor;
if( pCur->pNext ){
pCur->pNext->pPrev = pCur;
}
pBt->pCursor = pCur;
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
create_cursor_exception:
releasePage(pCur->pPage);
unlockBtreeIfUnused(pBt);
return rc;
}
SQLITE_PRIVATE int sqlite3BtreeCursor(
Btree *p, /* The btree */
int iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
BtCursor *pCur /* Write new cursor here */
){
int rc;
sqlite3BtreeEnter(p);
p->pBt->db = p->db;
rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
sqlite3BtreeLeave(p);
return rc;
}
SQLITE_PRIVATE int sqlite3BtreeCursorSize(){
return sizeof(BtCursor);
}
/*
** Close a cursor. The read lock on the database file is released
** when the last cursor is closed.
*/
SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
Btree *pBtree = pCur->pBtree;
if( pBtree ){
BtShared *pBt = pCur->pBt;
sqlite3BtreeEnter(pBtree);
pBt->db = pBtree->db;
clearCursorPosition(pCur);
if( pCur->pPrev ){
pCur->pPrev->pNext = pCur->pNext;
sqlite-amalgamation.c view on Meta::CPAN
releasePage(pCur->pPage);
unlockBtreeIfUnused(pBt);
invalidateOverflowCache(pCur);
/* sqlite3_free(pCur); */
sqlite3BtreeLeave(pBtree);
}
return SQLITE_OK;
}
/*
** Make a temporary cursor by filling in the fields of pTempCur.
** The temporary cursor is not on the cursor list for the Btree.
*/
SQLITE_PRIVATE void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){
assert( cursorHoldsMutex(pCur) );
memcpy(pTempCur, pCur, sizeof(*pCur));
pTempCur->pNext = 0;
pTempCur->pPrev = 0;
if( pTempCur->pPage ){
sqlite3PagerRef(pTempCur->pPage->pDbPage);
}
}
/*
** Delete a temporary cursor such as was made by the CreateTemporaryCursor()
** function above.
*/
SQLITE_PRIVATE void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
if( pCur->pPage ){
sqlite3PagerUnref(pCur->pPage->pDbPage);
}
}
/*
** Make sure the BtCursor* given in the argument has a valid
** BtCursor.info structure. If it is not already valid, call
** sqlite3BtreeParseCell() to fill it in.
**
sqlite-amalgamation.c view on Meta::CPAN
if( pCur->info.nSize==0 ){ \
sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); \
pCur->validNKey = 1; \
}else{ \
assertCellInfo(pCur); \
}
#endif /* _MSC_VER */
/*
** Set *pSize to the size of the buffer needed to hold the value of
** the key for the current entry. If the cursor is not pointing
** to a valid entry, *pSize is set to 0.
**
** For a table with the INTKEY flag set, this routine returns the key
** itself, not the number of bytes in the key.
*/
SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
int rc;
assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
if( pCur->eState==CURSOR_INVALID ){
*pSize = 0;
}else{
getCellInfo(pCur);
*pSize = pCur->info.nKey;
}
}
return rc;
}
/*
** Set *pSize to the number of bytes of data in the entry the
** cursor currently points to. Always return SQLITE_OK.
** Failure is not possible. If the cursor is not currently
** pointing to an entry (which can happen, for example, if
** the database is empty) then *pSize is set to 0.
*/
SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
int rc;
assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
if( pCur->eState==CURSOR_INVALID ){
/* Not pointing at a valid entry - set *pSize to 0. */
*pSize = 0;
}else{
getCellInfo(pCur);
*pSize = pCur->info.nData;
}
sqlite-amalgamation.c view on Meta::CPAN
memcpy(pPayload, pBuf, nByte);
}else{
/* Copy data from page to buffer (a read operation) */
memcpy(pBuf, pPayload, nByte);
}
return SQLITE_OK;
}
/*
** This function is used to read or overwrite payload information
** for the entry that the pCur cursor is pointing to. If the eOp
** parameter is 0, this is a read operation (data copied into
** buffer pBuf). If it is non-zero, a write (data copied from
** buffer pBuf).
**
** A total of "amt" bytes are read or written beginning at "offset".
** Data is read to or from the buffer pBuf.
**
** This routine does not make a distinction between key and data.
** It just reads or writes bytes from the payload area. Data might
** appear on the main page or be scattered out on multiple overflow
** pages.
**
** If the BtCursor.isIncrblobHandle flag is set, and the current
** cursor entry uses one or more overflow pages, this function
** allocates space for and lazily popluates the overflow page-list
** cache array (BtCursor.aOverflow). Subsequent calls use this
** cache to make seeking to the supplied offset more efficient.
**
** Once an overflow page-list cache has been allocated, it may be
** invalidated if some other cursor writes to the same table, or if
** the cursor is moved to a different row. Additionally, in auto-vacuum
** mode, the following events may invalidate an overflow page-list cache.
**
** * An incremental vacuum,
** * A commit in auto_vacuum="full" mode,
** * Creating a table (may require moving an overflow page).
*/
static int accessPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
int offset, /* Begin reading this far into payload */
int amt, /* Read this many bytes */
unsigned char *pBuf, /* Write the bytes into this buffer */
int skipKey, /* offset begins at data if this is true */
int eOp /* zero to read. non-zero to write. */
){
unsigned char *aPayload;
int rc = SQLITE_OK;
u32 nKey;
int iIdx = 0;
MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */
BtShared *pBt; /* Btree this cursor belongs to */
assert( pPage );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
assert( offset>=0 );
assert( cursorHoldsMutex(pCur) );
getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader;
nKey = (pPage->intKey ? 0 : pCur->info.nKey);
if( skipKey ){
offset += nKey;
}
if( offset+amt > nKey+pCur->info.nData ){
/* Trying to read or write past the end of the data is an error */
sqlite-amalgamation.c view on Meta::CPAN
}
}
if( rc==SQLITE_OK && amt>0 ){
return SQLITE_CORRUPT_BKPT;
}
return rc;
}
/*
** Read part of the key associated with cursor pCur. Exactly
** "amt" bytes will be transfered into pBuf[]. The transfer
** begins at "offset".
**
** Return SQLITE_OK on success or an error code if anything goes
** wrong. An error is returned if "offset+amt" is larger than
** the available payload.
*/
SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
int rc;
assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->pPage!=0 );
if( pCur->pPage->intKey ){
return SQLITE_CORRUPT_BKPT;
}
assert( pCur->pPage->intKey==0 );
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0);
}
return rc;
}
/*
** Read part of the data associated with cursor pCur. Exactly
** "amt" bytes will be transfered into pBuf[]. The transfer
** begins at "offset".
**
** Return SQLITE_OK on success or an error code if anything goes
** wrong. An error is returned if "offset+amt" is larger than
** the available payload.
*/
SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
int rc;
#ifndef SQLITE_OMIT_INCRBLOB
if ( pCur->eState==CURSOR_INVALID ){
return SQLITE_ABORT;
}
#endif
assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->pPage!=0 );
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
rc = accessPayload(pCur, offset, amt, pBuf, 1, 0);
}
return rc;
}
/*
** Return a pointer to payload information from the entry that the
** pCur cursor is pointing to. The pointer is to the beginning of
** the key if skipKey==0 and it points to the beginning of data if
** skipKey==1. The number of bytes of available key/data is written
** into *pAmt. If *pAmt==0, then the value returned will not be
** a valid pointer.
**
** This routine is an optimization. It is common for the entire key
** and data to fit on the local page and for there to be no overflow
** pages. When that is so, this routine can be used to access the
** key and data without making a copy. If the key and/or data spills
** onto overflow pages, then accessPayload() must be used to reassembly
sqlite-amalgamation.c view on Meta::CPAN
int *pAmt, /* Write the number of available bytes here */
int skipKey /* read beginning at data if this is true */
){
unsigned char *aPayload;
MemPage *pPage;
u32 nKey;
int nLocal;
assert( pCur!=0 && pCur->pPage!=0 );
assert( pCur->eState==CURSOR_VALID );
assert( cursorHoldsMutex(pCur) );
pPage = pCur->pPage;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur);
aPayload = pCur->info.pCell;
aPayload += pCur->info.nHeader;
if( pPage->intKey ){
nKey = 0;
}else{
nKey = pCur->info.nKey;
}
sqlite-amalgamation.c view on Meta::CPAN
if( nLocal>nKey ){
nLocal = nKey;
}
}
*pAmt = nLocal;
return aPayload;
}
/*
** For the entry that cursor pCur is point to, return as
** many bytes of the key or data as are available on the local
** b-tree page. Write the number of available bytes into *pAmt.
**
** The pointer returned is ephemeral. The key/data may move
** or be destroyed on the next call to any Btree routine,
** including calls from other threads against the same cache.
** Hence, a mutex on the BtShared should be held prior to calling
** this routine.
**
** These routines is used to get quick access to key and data
** in the common case where no overflow pages are used.
*/
SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
assert( cursorHoldsMutex(pCur) );
if( pCur->eState==CURSOR_VALID ){
return (const void*)fetchPayload(pCur, pAmt, 0);
}
return 0;
}
SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){
assert( cursorHoldsMutex(pCur) );
if( pCur->eState==CURSOR_VALID ){
return (const void*)fetchPayload(pCur, pAmt, 1);
}
return 0;
}
/*
** Move the cursor down to a new child page. The newPgno argument is the
** page number of the child page to move to.
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
int rc;
MemPage *pNewPage;
MemPage *pOldPage;
BtShared *pBt = pCur->pBt;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
if( rc ) return rc;
pNewPage->idxParent = pCur->idx;
pOldPage = pCur->pPage;
pOldPage->idxShift = 0;
releasePage(pOldPage);
pCur->pPage = pNewPage;
pCur->idx = 0;
pCur->info.nSize = 0;
sqlite-amalgamation.c view on Meta::CPAN
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pParent = pPage->pParent;
if( pParent==0 ) return 1;
if( pParent->pgno>1 ) return 0;
if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1;
return 0;
}
/*
** Move the cursor up to the parent page.
**
** pCur->idx is set to the cell index that contains the pointer
** to the page we are coming from. If we are coming from the
** right-most child page then pCur->idx is set to one more than
** the largest cell index.
*/
SQLITE_PRIVATE void sqlite3BtreeMoveToParent(BtCursor *pCur){
MemPage *pParent;
MemPage *pPage;
int idxParent;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage;
assert( pPage!=0 );
assert( !sqlite3BtreeIsRootPage(pPage) );
pParent = pPage->pParent;
assert( pParent!=0 );
idxParent = pPage->idxParent;
sqlite3PagerRef(pParent->pDbPage);
releasePage(pPage);
pCur->pPage = pParent;
pCur->info.nSize = 0;
pCur->validNKey = 0;
assert( pParent->idxShift==0 );
pCur->idx = idxParent;
}
/*
** Move the cursor to the root page
*/
static int moveToRoot(BtCursor *pCur){
MemPage *pRoot;
int rc = SQLITE_OK;
Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt;
assert( cursorHoldsMutex(pCur) );
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
if( pCur->eState>=CURSOR_REQUIRESEEK ){
if( pCur->eState==CURSOR_FAULT ){
return pCur->skip;
}
clearCursorPosition(pCur);
}
pRoot = pCur->pPage;
sqlite-amalgamation.c view on Meta::CPAN
subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
assert( subpage>0 );
pCur->eState = CURSOR_VALID;
rc = moveToChild(pCur, subpage);
}
pCur->eState = ((pCur->pPage->nCell>0)?CURSOR_VALID:CURSOR_INVALID);
return rc;
}
/*
** Move the cursor down to the left-most leaf entry beneath the
** entry to which it is currently pointing.
**
** The left-most leaf is the one with the smallest key - the first
** in ascending order.
*/
static int moveToLeftmost(BtCursor *pCur){
Pgno pgno;
int rc = SQLITE_OK;
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
pgno = get4byte(findCell(pPage, pCur->idx));
rc = moveToChild(pCur, pgno);
}
return rc;
}
/*
** Move the cursor down to the right-most leaf entry beneath the
** page to which it is currently pointing. Notice the difference
** between moveToLeftmost() and moveToRightmost(). moveToLeftmost()
** finds the left-most entry beneath the *entry* whereas moveToRightmost()
** finds the right-most entry beneath the *page*.
**
** The right-most entry is the one with the largest key - the last
** key in ascending order.
*/
static int moveToRightmost(BtCursor *pCur){
Pgno pgno;
int rc = SQLITE_OK;
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->idx = pPage->nCell;
rc = moveToChild(pCur, pgno);
}
if( rc==SQLITE_OK ){
pCur->idx = pPage->nCell - 1;
pCur->info.nSize = 0;
pCur->validNKey = 0;
}
return SQLITE_OK;
}
/* Move the cursor to the first entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
*/
SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
int rc;
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
if( pCur->eState==CURSOR_INVALID ){
assert( pCur->pPage->nCell==0 );
*pRes = 1;
rc = SQLITE_OK;
}else{
assert( pCur->pPage->nCell>0 );
*pRes = 0;
rc = moveToLeftmost(pCur);
}
}
return rc;
}
/* Move the cursor to the last entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
*/
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
if( CURSOR_INVALID==pCur->eState ){
assert( pCur->pPage->nCell==0 );
*pRes = 1;
}else{
assert( pCur->eState==CURSOR_VALID );
*pRes = 0;
rc = moveToRightmost(pCur);
getCellInfo(pCur);
pCur->atLast = rc==SQLITE_OK;
}
}
return rc;
}
/* Move the cursor so that it points to an entry near the key
** specified by pKey/nKey/pUnKey. Return a success code.
**
** For INTKEY tables, only the nKey parameter is used. pKey
** and pUnKey must be NULL. For index tables, either pUnKey
** must point to a key that has already been unpacked, or else
** pKey/nKey describes a blob containing the key.
**
** If an exact match is not found, then the cursor is always
** left pointing at a leaf page which would hold the entry if it
** were present. The cursor might point to an entry that comes
** before or after the key.
**
** The result of comparing the key with the entry to which the
** cursor is written to *pRes if pRes!=NULL. The meaning of
** this value is as follows:
**
** *pRes<0 The cursor is left pointing at an entry that
** is smaller than pKey or if the table is empty
** and the cursor is therefore left point to nothing.
**
** *pRes==0 The cursor is left pointing at an entry that
** exactly matches pKey.
**
** *pRes>0 The cursor is left pointing at an entry that
** is larger than pKey.
**
*/
SQLITE_PRIVATE int sqlite3BtreeMoveto(
BtCursor *pCur, /* The cursor to be moved */
const void *pKey, /* The key content for indices. Not used by tables */
UnpackedRecord *pUnKey,/* Unpacked version of pKey */
i64 nKey, /* Size of pKey. Or the key for tables */
int biasRight, /* If true, bias the search to the high end */
int *pRes /* Search result flag */
){
int rc;
char aSpace[200];
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */
if( pCur->eState==CURSOR_VALID && pCur->validNKey && pCur->pPage->intKey ){
if( pCur->info.nKey==nKey ){
*pRes = 0;
return SQLITE_OK;
}
if( pCur->atLast && pCur->info.nKey<nKey ){
*pRes = -1;
return SQLITE_OK;
}
sqlite-amalgamation.c view on Meta::CPAN
if( pKey ){
/* If we created our own unpacked key at the top of this
** procedure, then destroy that key before returning. */
sqlite3VdbeDeleteUnpackedRecord(pUnKey);
}
return rc;
}
/*
** Return TRUE if the cursor is not pointing at an entry of the table.
**
** TRUE will be returned after a call to sqlite3BtreeNext() moves
** past the last entry in the table or sqlite3BtreePrev() moves past
** the first entry. TRUE is also returned if the table is empty.
*/
SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
/* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries
** have been deleted? This API will need to change to return an error code
** as well as the boolean result value.
*/
return (CURSOR_VALID!=pCur->eState);
}
/*
** Return the database connection handle for a cursor.
*/
SQLITE_PRIVATE sqlite3 *sqlite3BtreeCursorDb(const BtCursor *pCur){
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
return pCur->pBtree->db;
}
/*
** Advance the cursor to the next entry in the database. If
** successful then set *pRes=0. If the cursor
** was already pointing to the last entry in the database before
** this routine was called, then set *pRes=1.
*/
SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
int rc;
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
assert( pRes!=0 );
pPage = pCur->pPage;
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
}
sqlite-amalgamation.c view on Meta::CPAN
*pRes = 0;
if( pPage->leaf ){
return SQLITE_OK;
}
rc = moveToLeftmost(pCur);
return rc;
}
/*
** Step the cursor to the back to the previous entry in the database. If
** successful then set *pRes=0. If the cursor
** was already pointing to the first entry in the database before
** this routine was called, then set *pRes=1.
*/
SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
int rc;
Pgno pgno;
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
pCur->atLast = 0;
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
}
if( pCur->skip<0 ){
sqlite-amalgamation.c view on Meta::CPAN
}else{
if( pPage->nOverflow>0 ||
(!insert && pPage->nFree>pPage->pBt->usableSize*2/3) ){
rc = balance_nonroot(pPage);
}
}
return rc;
}
/*
** This routine checks all cursors that point to table pgnoRoot.
** If any of those cursors were opened with wrFlag==0 in a different
** database connection (a database connection that shares the pager
** cache with the current connection) and that other connection
** is not in the ReadUncommmitted state, then this routine returns
** SQLITE_LOCKED.
**
** As well as cursors with wrFlag==0, cursors with wrFlag==1 and
** isIncrblobHandle==1 are also considered 'read' cursors. Incremental
** blob cursors are used for both reading and writing.
**
** When pgnoRoot is the root page of an intkey table, this function is also
** responsible for invalidating incremental blob cursors when the table row
** on which they are opened is deleted or modified. Cursors are invalidated
** according to the following rules:
**
** 1) When BtreeClearTable() is called to completely delete the contents
** of a B-Tree table, pExclude is set to zero and parameter iRow is
** set to non-zero. In this case all incremental blob cursors open
** on the table rooted at pgnoRoot are invalidated.
**
** 2) When BtreeInsert(), BtreeDelete() or BtreePutData() is called to
** modify a table row via an SQL statement, pExclude is set to the
** write cursor used to do the modification and parameter iRow is set
** to the integer row id of the B-Tree entry being modified. Unless
** pExclude is itself an incremental blob cursor, then all incremental
** blob cursors open on row iRow of the B-Tree are invalidated.
**
** 3) If both pExclude and iRow are set to zero, no incremental blob
** cursors are invalidated.
*/
static int checkReadLocks(
Btree *pBtree,
Pgno pgnoRoot,
BtCursor *pExclude,
i64 iRow
){
BtCursor *p;
BtShared *pBt = pBtree->pBt;
sqlite3 *db = pBtree->db;
sqlite-amalgamation.c view on Meta::CPAN
(dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0) ){
return SQLITE_LOCKED;
}
}
}
return SQLITE_OK;
}
/*
** Insert a new record into the BTree. The key is given by (pKey,nKey)
** and the data is given by (pData,nData). The cursor is used only to
** define what table the record should be inserted into. The cursor
** is left pointing at a random location.
**
** For an INTKEY table, only the nKey value of the key is used. pKey is
** ignored. For a ZERODATA table, the pData and nData are both ignored.
*/
SQLITE_PRIVATE int sqlite3BtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */
const void *pKey, i64 nKey, /* The key of the new record */
const void *pData, int nData, /* The data of the new record */
int nZero, /* Number of extra 0 bytes to append to data */
int appendBias /* True if this is likely an append */
){
int rc;
int loc;
int szNew;
MemPage *pPage;
Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt;
unsigned char *oldCell;
unsigned char *newCell = 0;
assert( cursorHoldsMutex(pCur) );
if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before doing an insert */
rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
return rc;
}
assert( !pBt->readOnly );
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Cursor not open for writing */
}
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur, nKey) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
if( pCur->eState==CURSOR_FAULT ){
return pCur->skip;
}
/* Save the positions of any other cursors open on this table */
clearCursorPosition(pCur);
if(
SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) ||
SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, 0, nKey, appendBias, &loc))
){
return rc;
}
pPage = pCur->pPage;
assert( pPage->intKey || nKey>=0 );
sqlite-amalgamation.c view on Meta::CPAN
if( rc!=SQLITE_OK ) goto end_insert;
rc = balance(pPage, 1);
if( rc==SQLITE_OK ){
moveToRoot(pCur);
}
end_insert:
return rc;
}
/*
** Delete the entry that the cursor is pointing to. The cursor
** is left pointing at a random location.
*/
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
MemPage *pPage = pCur->pPage;
unsigned char *pCell;
int rc;
Pgno pgnoChild = 0;
Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt;
assert( cursorHoldsMutex(pCur) );
assert( pPage->isInit );
if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before doing a delete */
rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
return rc;
}
assert( !pBt->readOnly );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skip;
}
if( pCur->idx >= pPage->nCell ){
return SQLITE_ERROR; /* The cursor is not pointing to anything */
}
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Did not open this cursor for writing */
}
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur, pCur->info.nKey) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
/* Restore the current cursor position (a no-op if the cursor is not in
** CURSOR_REQUIRESEEK state) and save the positions of any other cursors
** open on the same table. Then call sqlite3PagerWrite() on the page
** that the entry will be deleted from.
*/
if(
(rc = restoreCursorPosition(pCur))!=0 ||
(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 ||
(rc = sqlite3PagerWrite(pPage->pDbPage))!=0
){
return rc;
}
sqlite-amalgamation.c view on Meta::CPAN
return rc;
}
#else
if( pBt->autoVacuum ){
Pgno pgnoMove; /* Move a page here to make room for the root-page */
MemPage *pPageMove; /* The page to move to. */
/* Creating a new table may probably require moving an existing database
** to make room for the new tables root page. In case this page turns
** out to be an overflow page, delete all overflow page-map caches
** held by open cursors.
*/
invalidateAllOverflowCache(pBt);
/* Read the value of meta[3] from the database to determine where the
** root page of the new table should go. meta[3] is the largest root-page
** created so far, so the new root-page is (meta[3]+1).
*/
rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot);
if( rc!=SQLITE_OK ){
return rc;
sqlite-amalgamation.c view on Meta::CPAN
releasePage(pPage);
return rc;
}
/*
** Delete all information from a single table in the database. iTable is
** the page number of the root of the table. After this routine returns,
** the root page is empty, but still exists.
**
** This routine will fail with SQLITE_LOCKED if there are any open
** read cursors on the table. Open write cursors are moved to the
** root of the table.
*/
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable){
int rc;
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
pBt->db = p->db;
if( p->inTrans!=TRANS_WRITE ){
rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}else if( (rc = checkReadLocks(p, iTable, 0, 1))!=SQLITE_OK ){
sqlite-amalgamation.c view on Meta::CPAN
sqlite3BtreeLeave(p);
return rc;
}
/*
** Erase all information in a table and add the root of the table to
** the freelist. Except, the root of the principle table (the one on
** page 1) is never added to the freelist.
**
** This routine will fail with SQLITE_LOCKED if there are any open
** cursors on the table.
**
** If AUTOVACUUM is enabled and the page at iTable is not the last
** root page in the database file, then the last root page
** in the database file is moved into the slot formerly occupied by
** iTable and that last slot formerly occupied by the last root page
** is added to the freelist instead of iTable. In this say, all
** root pages are kept at the beginning of the database file, which
** is necessary for AUTOVACUUM to work right. *piMoved is set to the
** page number that used to be the last root page in the file before
** the move. If no page gets moved, *piMoved is set to 0.
sqlite-amalgamation.c view on Meta::CPAN
static int btreeDropTable(Btree *p, int iTable, int *piMoved){
int rc;
MemPage *pPage = 0;
BtShared *pBt = p->pBt;
assert( sqlite3BtreeHoldsMutex(p) );
if( p->inTrans!=TRANS_WRITE ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
/* It is illegal to drop a table if any cursors are open on the
** database. This is because in auto-vacuum mode the backend may
** need to move another root-page to fill a gap left by the deleted
** root page. If an open cursor was using this page a problem would
** occur.
*/
if( pBt->pCursor ){
return SQLITE_LOCKED;
}
rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable);
if( rc ){
sqlite-amalgamation.c view on Meta::CPAN
pBt->incrVacuum = iMeta;
}
#endif
}
}
sqlite3BtreeLeave(p);
return rc;
}
/*
** Return the flag byte at the beginning of the page that the cursor
** is currently pointing to.
*/
SQLITE_PRIVATE int sqlite3BtreeFlags(BtCursor *pCur){
/* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call
** restoreCursorPosition() here.
*/
MemPage *pPage;
restoreCursorPosition(pCur);
pPage = pCur->pPage;
assert( cursorHoldsMutex(pCur) );
assert( pPage->pBt==pCur->pBt );
return pPage ? pPage->aData[pPage->hdrOffset] : 0;
}
/*
** Return the pager associated with a BTree. This routine is used for
** testing and debugging only.
*/
SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){
sqlite-amalgamation.c view on Meta::CPAN
rc = lockTable(p, iTab, lockType);
}
sqlite3BtreeLeave(p);
}
return rc;
}
#endif
#ifndef SQLITE_OMIT_INCRBLOB
/*
** Argument pCsr must be a cursor opened for writing on an
** INTKEY table currently pointing at a valid table entry.
** This function modifies the data stored as part of that entry.
** Only the data content may only be modified, it is not possible
** to change the length of the data stored.
*/
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
assert( cursorHoldsMutex(pCsr) );
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
assert(pCsr->isIncrblobHandle);
restoreCursorPosition(pCsr);
assert( pCsr->eState!=CURSOR_REQUIRESEEK );
if( pCsr->eState!=CURSOR_VALID ){
return SQLITE_ABORT;
}
/* Check some preconditions:
** (a) the cursor is open for writing,
** (b) there is no read-lock on the table being modified and
** (c) the cursor points at a valid row of an intKey table.
*/
if( !pCsr->wrFlag ){
return SQLITE_READONLY;
}
assert( !pCsr->pBt->readOnly
&& pCsr->pBt->inTransaction==TRANS_WRITE );
if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr, 0) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
if( pCsr->eState==CURSOR_INVALID || !pCsr->pPage->intKey ){
return SQLITE_ERROR;
}
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 0, 1);
}
/*
** Set a flag on this cursor to cache the locations of pages from the
** overflow list for the current row. This is used by cursors opened
** for incremental blob IO only.
**
** This function sets a flag only. The actual page location cache
** (stored in BtCursor.aOverflow[]) is allocated and used by function
** accessPayload() (the worker function for sqlite3BtreeData() and
** sqlite3BtreePutData()).
*/
SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert(!pCur->isIncrblobHandle);
assert(!pCur->aOverflow);
pCur->isIncrblobHandle = 1;
}
#endif
/************** End of btree.c ***********************************************/
/************** Begin file vdbefifo.c ****************************************/
/*
sqlite-amalgamation.c view on Meta::CPAN
** After the VDBE has be prepped, it can be executed by one or more
** calls to sqlite3VdbeExec().
**
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
** VDBE_MAGIC_RUN.
*/
SQLITE_PRIVATE void sqlite3VdbeMakeReady(
Vdbe *p, /* The VDBE */
int nVar, /* Number of '?' see in the SQL statement */
int nMem, /* Number of memory cells to allocate */
int nCursor, /* Number of cursors to allocate */
int isExplain /* True if the EXPLAIN keywords is present */
){
int n;
sqlite3 *db = p->db;
assert( p!=0 );
assert( p->magic==VDBE_MAGIC_INIT );
/* There should be at least one opcode.
*/
assert( p->nOp>0 );
/* Set the magic to VDBE_MAGIC_RUN sooner rather than later. This
* is because the call to resizeOpArray() below may shrink the
* p->aOp[] array to save memory if called when in VDBE_MAGIC_RUN
* state.
*/
p->magic = VDBE_MAGIC_RUN;
/* For each cursor required, also allocate a memory cell. Memory
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
** the vdbe program. Instead they are used to allocate space for
** Cursor/BtCursor structures. The blob of memory associated with
** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
** stores the blob of memory associated with cursor 1, etc.
**
** See also: allocateCursor().
*/
nMem += nCursor;
/*
** Allocation space for registers.
*/
if( p->aMem==0 ){
int nArg; /* Maximum number of args passed to a user function. */
sqlite-amalgamation.c view on Meta::CPAN
int i;
for(i=0; i<p->nOp; i++){
p->aOp[i].cnt = 0;
p->aOp[i].cycles = 0;
}
}
#endif
}
/*
** Close a VDBE cursor and release all the resources that cursor
** happens to hold.
*/
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
if( pCx==0 ){
return;
}
if( pCx->pBt ){
sqlite3BtreeClose(pCx->pBt);
/* The pCx->pCursor will be close automatically, if it exists, by
** the call above. */
}else if( pCx->pCursor ){
sqlite3BtreeCloseCursor(pCx->pCursor);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pCx->pVtabCursor ){
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
const sqlite3_module *pModule = pCx->pModule;
p->inVtabMethod = 1;
(void)sqlite3SafetyOff(p->db);
pModule->xClose(pVtabCursor);
(void)sqlite3SafetyOn(p->db);
p->inVtabMethod = 0;
}
#endif
if( !pCx->ephemPseudoTable ){
sqlite3DbFree(p->db, pCx->pData);
}
}
/*
** Close all cursors except for VTab cursors that are currently
** in use.
*/
static void closeAllCursorsExceptActiveVtabs(Vdbe *p){
int i;
if( p->apCsr==0 ) return;
for(i=0; i<p->nCursor; i++){
Cursor *pC = p->apCsr[i];
if( pC && (!p->inVtabMethod || !pC->pVtabCursor) ){
sqlite3VdbeFreeCursor(p, pC);
p->apCsr[i] = 0;
}
}
}
/*
** Clean up the VM after execution.
**
** This routine will automatically close any cursors, lists, and/or
** sorters that were left open. It also deletes the values of
** variables in the aVar[] array.
*/
static void Cleanup(Vdbe *p){
int i;
sqlite3 *db = p->db;
closeAllCursorsExceptActiveVtabs(p);
for(i=1; i<=p->nMem; i++){
MemSetTypeFlag(&p->aMem[i], MEM_Null);
}
sqlite-amalgamation.c view on Meta::CPAN
p = p->pNext;
}
assert( cnt==db->activeVdbeCnt );
}
#else
#define checkActiveVdbeCnt(x)
#endif
/*
** For every Btree that in database connection db which
** has been modified, "trip" or invalidate each cursor in
** that Btree might have been modified so that the cursor
** can never be used again. This happens when a rollback
*** occurs. We have to trip all the other cursors, even
** cursor from other VMs in different database connections,
** so that none of them try to use the data at which they
** were pointing and which now may have been changed due
** to the rollback.
**
** Remember that a rollback can delete tables complete and
** reorder rootpages. So it is not sufficient just to save
** the state of the cursor. We have to invalidate the cursor
** so that it is never used again.
*/
static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
int i;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
if( p && sqlite3BtreeIsInTrans(p) ){
sqlite3BtreeTripAllCursors(p, SQLITE_ABORT);
}
}
sqlite-amalgamation.c view on Meta::CPAN
sqlite3DbFree(db, &p->aMem[1]);
}
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
p->magic = VDBE_MAGIC_DEAD;
sqlite3DbFree(db, p);
}
/*
** If a MoveTo operation is pending on the given cursor, then do that
** MoveTo now. Return an error code. If no MoveTo is pending, this
** routine does nothing and returns SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(Cursor *p){
if( p->deferredMoveto ){
int res, rc;
#ifdef SQLITE_TEST
extern int sqlite3_search_count;
#endif
assert( p->isTable );
sqlite-amalgamation.c view on Meta::CPAN
(void)getVarint32((u8*)m.z, szHdr);
(void)getVarint32((u8*)&m.z[szHdr-1], typeRowid);
lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v);
*rowid = v.u.i;
sqlite3VdbeMemRelease(&m);
return SQLITE_OK;
}
/*
** Compare the key of the index entry that cursor pC is point to against
** the key string in pKey (of length nKey). Write into *pRes a number
** that is negative, zero, or positive if pC is less than, equal to,
** or greater than pKey. Return SQLITE_OK on success.
**
** pKey is either created without a rowid or is truncated so that it
** omits the rowid at the end. The rowid at the end of the index entry
** is ignored as well.
*/
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
Cursor *pC, /* The cursor to compare against */
UnpackedRecord *pUnpacked,
int nKey, const u8 *pKey, /* The key to compare */
int *res /* Write the comparison result here */
){
i64 nCellKey = 0;
int rc;
BtCursor *pCur = pC->pCursor;
int lenRowid;
Mem m;
UnpackedRecord *pRec;
sqlite-amalgamation.c view on Meta::CPAN
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files. The formatting
** of the code in this file is, therefore, important. See other comments
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.772 2008/08/02 15:10:09 danielk1977 Exp $
*/
/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveXX, OP_Next, or OP_Prev opcodes. The test
** procedures use this information to make sure that indices are
** working correctly. This variable has no function other than to
** help verify the correct operation of the library.
*/
#ifdef SQLITE_TEST
SQLITE_API int sqlite3_search_count = 0;
#endif
/*
sqlite-amalgamation.c view on Meta::CPAN
/*
** Return true if an opcode has any of the OPFLG_xxx properties
** specified by mask.
*/
SQLITE_PRIVATE int sqlite3VdbeOpcodeHasProperty(int opcode, int mask){
assert( opcode>0 && opcode<sizeof(opcodeProperty) );
return (opcodeProperty[opcode]&mask)!=0;
}
/*
** Allocate cursor number iCur. Return a pointer to it. Return NULL
** if we run out of memory.
*/
static Cursor *allocateCursor(
Vdbe *p,
int iCur,
Op *pOp,
int iDb,
int isBtreeCursor
){
/* Find the memory cell that will be used to store the blob of memory
** required for this Cursor structure. It is convenient to use a
** vdbe memory cell to manage the memory allocation required for a
** Cursor structure for the following reasons:
**
** * Sometimes cursor numbers are used for a couple of different
** purposes in a vdbe program. The different uses might require
** different sized allocations. Memory cells provide growable
** allocations.
**
** * When using ENABLE_MEMORY_MANAGEMENT, memory cell buffers can
** be freed lazily via the sqlite3_release_memory() API. This
** minimizes the number of malloc calls made by the system.
**
** Memory cells for cursors are allocated at the top of the address
** space. Memory cell (p->nMem) corresponds to cursor 0. Space for
** cursor 1 is managed by memory cell (p->nMem-1), etc.
*/
Mem *pMem = &p->aMem[p->nMem-iCur];
int nByte;
Cursor *pCx = 0;
/* If the opcode of pOp is OP_SetNumColumns, then pOp->p2 contains
** the number of fields in the records contained in the table or
** index being opened. Use this to reserve space for the
** Cursor.aType[] array.
*/
sqlite-amalgamation.c view on Meta::CPAN
pcDest = pIn1->u.i;
pIn1->u.i = pc;
REGISTER_TRACE(pOp->p1, pIn1);
pc = pcDest;
break;
}
/* Opcode: Halt P1 P2 * P4 *
**
** Exit immediately. All open cursors, Fifos, etc are closed
** automatically.
**
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
** or sqlite3_finalize(). For a normal halt, this should be SQLITE_OK (0).
** For errors, it can be some other value. If P1!=0 then P2 will determine
** whether or not to rollback the current transaction. Do not rollback
** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort,
** then back out all changes that have occurred during this execution of the
** VDBE, but do not rollback the transaction.
**
sqlite-amalgamation.c view on Meta::CPAN
** structure to provide access to the top P1 values as the result
** row.
*/
case OP_ResultRow: {
Mem *pMem;
int i;
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
assert( pOp->p1+pOp->p2<=p->nMem );
/* Invalidate all ephemeral cursor row caches */
p->cacheCtr = (p->cacheCtr + 2)|1;
/* Make sure the results of the current row are \000 terminated
** and have an assigned type. The results are de-ephemeralized as
** as side effect.
*/
pMem = p->pResultSet = &p->aMem[pOp->p1];
for(i=0; i<pOp->p2; i++){
sqlite3VdbeMemNulTerminate(&pMem[i]);
storeTypeInfo(&pMem[i], encoding);
sqlite-amalgamation.c view on Meta::CPAN
*/
case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
if( (pIn1->flags & MEM_Null)==0 ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: SetNumColumns * P2 * * *
**
** This opcode sets the number of columns for the cursor opened by the
** following instruction to P2.
**
** An OP_SetNumColumns is only useful if it occurs immediately before
** one of the following opcodes:
**
** OpenRead
** OpenWrite
** OpenPseudo
**
** If the OP_Column opcode is to be executed on a cursor, then
** this opcode must be present immediately before the opcode that
** opens the cursor.
*/
case OP_SetNumColumns: {
break;
}
/* Opcode: Column P1 P2 P3 P4 *
**
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
** information about the format of the data.) Extract the P2-th column
** from this record. If there are less that (P2+1)
** values in the record, extract a NULL.
**
** The value extracted is stored in register P3.
**
** If the KeyAsData opcode has previously executed on this cursor, then the
** field might be extracted from the key rather than the data.
**
** If the column contains fewer than P2 fields, then extract a NULL. Or,
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
*/
case OP_Column: {
u32 payloadSize; /* Number of bytes in the record */
int p1 = pOp->p1; /* P1 value of the opcode */
int p2 = pOp->p2; /* column number to retrieve */
Cursor *pC = 0; /* The VDBE cursor */
char *zRec; /* Pointer to complete record-data */
BtCursor *pCrsr; /* The BTree cursor */
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
u32 nField; /* number of fields in the record */
int len; /* The length of the serialized data for the column */
int i; /* Loop counter */
char *zData; /* Part of the record being decoded */
Mem *pDest; /* Where to write the extracted value */
Mem sMem; /* For storing the record being decoded */
sMem.flags = 0;
sqlite-amalgamation.c view on Meta::CPAN
assert( p1<p->nCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
pDest = &p->aMem[pOp->p3];
MemSetTypeFlag(pDest, MEM_Null);
/* This block sets the variable payloadSize to be the total number of
** bytes in the record.
**
** zRec is set to be the complete text of the record if it is available.
** The complete record text is always available for pseudo-tables
** If the record is stored in a cursor, the complete record text
** might be available in the pC->aRow cache. Or it might not be.
** If the data is unavailable, zRec is set to NULL.
**
** We also compute the number of columns in the record. For cursors,
** the number of columns is stored in the Cursor.nField element.
*/
pC = p->apCsr[p1];
assert( pC!=0 );
#ifndef SQLITE_OMIT_VIRTUALTABLE
assert( pC->pVtabCursor==0 );
#endif
if( pC->pCursor!=0 ){
/* The record is stored in a B-Tree */
rc = sqlite3VdbeCursorMoveto(pC);
sqlite-amalgamation.c view on Meta::CPAN
assert( pDest->flags&MEM_Null );
goto op_column_out;
}
if( payloadSize>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
assert( p2<nField );
/* Read and parse the table header. Store the results of the parse
** into the record header cache fields of the cursor.
*/
aType = pC->aType;
if( pC->cacheStatus==p->cacheCtr ){
aOffset = pC->aOffset;
}else{
u8 *zIdx; /* Index into header */
u8 *zEndHdr; /* Pointer to first byte after the header */
u32 offset; /* Offset into the data */
int szHdrSz; /* Size of the header size field at start of record */
int avail; /* Number of bytes of available data */
sqlite-amalgamation.c view on Meta::CPAN
** P3==2 is the recommended pager cache size, and so forth. P1==0 is
** the main database file and P1==1 is the database file used to store
** temporary tables.
**
** If P1 is negative, then this is a request to read the size of a
** databases free-list. P3 must be set to 1 in this case. The actual
** database accessed is ((P1+1)*-1). For example, a P1 parameter of -1
** corresponds to database 0 ("main"), a P1 of -2 is database 1 ("temp").
**
** There must be a read-lock on the database (either a transaction
** must be started or there must be an open cursor) before
** executing this instruction.
*/
case OP_ReadCookie: { /* out2-prerelease */
int iMeta;
int iDb = pOp->p1;
int iCookie = pOp->p3;
assert( pOp->p3<SQLITE_N_BTREE_META );
if( iDb<0 ){
iDb = (-1*(iDb+1));
sqlite-amalgamation.c view on Meta::CPAN
}
sqlite3ExpirePreparedStatements(db);
rc = SQLITE_SCHEMA;
}
break;
}
/* Opcode: OpenRead P1 P2 P3 P4 P5
**
** Open a read-only cursor for the database table whose root page is
** P2 in a database file. The database file is determined by P3.
** P3==0 means the main database, P3==1 means the database used for
** temporary tables, and P3>1 means used the corresponding attached
** database. Give the new cursor an identifier of P1. The P1
** values need not be contiguous but all P1 values should be small integers.
** It is an error for P1 to be negative.
**
** If P5!=0 then use the content of register P2 as the root page, not
** the value of P2 itself.
**
** There will be a read lock on the database whenever there is an
** open cursor. If the database was unlocked prior to this instruction
** then a read lock is acquired as part of this instruction. A read
** lock allows other processes to read the database but prohibits
** any other process from modifying the database. The read lock is
** released when all cursors are closed. If this instruction attempts
** to get a read lock but fails, the script terminates with an
** SQLITE_BUSY error code.
**
** The P4 value is a pointer to a KeyInfo structure that defines the
** content and collating sequence of indices. P4 is NULL for cursors
** that are not pointing to indices.
**
** See also OpenWrite.
*/
/* Opcode: OpenWrite P1 P2 P3 P4 P5
**
** Open a read/write cursor named P1 on the table or index whose root
** page is P2. Or if P5!=0 use the content of register P2 to find the
** root page.
**
** The P4 value is a pointer to a KeyInfo structure that defines the
** content and collating sequence of indices. P4 is NULL for cursors
** that are not pointing to indices.
**
** This instruction works just like OpenRead except that it opens the cursor
** in read/write mode. For a given table, there can be one or more read-only
** cursors or a single read/write cursor but not both.
**
** See also OpenRead.
*/
case OP_OpenRead:
case OP_OpenWrite: {
int i = pOp->p1;
int p2 = pOp->p2;
int iDb = pOp->p3;
int wrFlag;
Btree *pX;
sqlite-amalgamation.c view on Meta::CPAN
}
default: {
goto abort_due_to_error;
}
}
break;
}
/* Opcode: OpenEphemeral P1 P2 * P4 *
**
** Open a new cursor P1 to a transient table.
** The cursor is always opened read/write even if
** the main database is read-only. The transient or virtual
** table is deleted automatically when the cursor is closed.
**
** P2 is the number of columns in the virtual table.
** The cursor points to a BTree table if P4==0 and to a BTree index
** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index.
**
** This opcode was once called OpenTemp. But that created
** confusion because the term "temp table", might refer either
** to a TEMP table at the SQL level, or to a table opened by
** this opcode. Then this opcode was call OpenVirtual. But
** that created confusion with the whole virtual-table idea.
*/
case OP_OpenEphemeral: {
sqlite-amalgamation.c view on Meta::CPAN
pCx->isTable = 1;
pCx->pIncrKey = &pCx->bogusIncrKey;
}
}
pCx->isIndex = !pCx->isTable;
break;
}
/* Opcode: OpenPseudo P1 P2 * * *
**
** Open a new cursor that points to a fake table that contains a single
** row of data. Any attempt to write a second row of data causes the
** first row to be deleted. All data is deleted when the cursor is
** closed.
**
** A pseudo-table created by this opcode is useful for holding the
** NEW or OLD tables in a trigger. Also used to hold the a single
** row output from the sorter so that the row can be decomposed into
** individual columns using the OP_Column opcode.
**
** When OP_Insert is executed to insert a row in to the pseudo table,
** the pseudo-table cursor may or may not make it's own copy of the
** original row data. If P2 is 0, then the pseudo-table will copy the
** original row data. Otherwise, a pointer to the original memory cell
** is stored. In this case, the vdbe program must ensure that the
** memory cell containing the row data is not overwritten until the
** pseudo table is closed (or a new row is inserted into it).
*/
case OP_OpenPseudo: {
int i = pOp->p1;
Cursor *pCx;
assert( i>=0 );
sqlite-amalgamation.c view on Meta::CPAN
pCx->pseudoTable = 1;
pCx->ephemPseudoTable = pOp->p2;
pCx->pIncrKey = &pCx->bogusIncrKey;
pCx->isTable = 1;
pCx->isIndex = 0;
break;
}
/* Opcode: Close P1 * * * *
**
** Close a cursor previously opened as P1. If P1 is not
** currently open, this instruction is a no-op.
*/
case OP_Close: {
int i = pOp->p1;
assert( i>=0 && i<p->nCursor );
sqlite3VdbeFreeCursor(p, p->apCsr[i]);
p->apCsr[i] = 0;
break;
}
/* Opcode: MoveGe P1 P2 P3 P4 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the integer value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the smallest entry that
** is greater than or equal to the key value. If there are no records
** greater than or equal to the key and P2 is not zero, then jump to P2.
**
** A special feature of this opcode (and different from the
** related OP_MoveGt, OP_MoveLt, and OP_MoveLe) is that if P2 is
** zero and P1 is an SQL table (a b-tree with integer keys) then
** the seek is deferred until it is actually needed. It might be
** the case that the cursor is never accessed. By deferring the
** seek, we avoid unnecessary seeks.
**
** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe
*/
/* Opcode: MoveGt P1 P2 P3 P4 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the integer value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the smallest entry that
** is greater than the key value. If there are no records greater than
** the key and P2 is not zero, then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe
*/
/* Opcode: MoveLt P1 P2 P3 P4 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the integer value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the largest entry that
** is less than the key value. If there are no records less than
** the key and P2 is not zero, then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe
*/
/* Opcode: MoveLe P1 P2 P3 P4 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the integer value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the largest entry that
** is less than or equal to the key value. If there are no records
** less than or equal to the key and P2 is not zero, then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt
*/
case OP_MoveLt: /* jump, in3 */
case OP_MoveLe: /* jump, in3 */
case OP_MoveGe: /* jump, in3 */
case OP_MoveGt: { /* jump, in3 */
int i = pOp->p1;
sqlite-amalgamation.c view on Meta::CPAN
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: Found P1 P2 P3 * *
**
** Register P3 holds a blob constructed by MakeRecord. P1 is an index.
** If an entry that matches the value in register p3 exists in P1 then
** jump to P2. If the P3 value does not match any entry in P1
** then fall thru. The P1 cursor is left pointing at the matching entry
** if it exists.
**
** This instruction is used to implement the IN operator where the
** left-hand side is a SELECT statement. P1 may be a true index, or it
** may be a temporary index that holds the results of the SELECT
** statement. This instruction is also used to implement the
** DISTINCT keyword in SELECT statements.
**
** This instruction checks if index P1 contains a record for which
** the first N serialized values exactly match the N serialized values
** in the record in register P3, where N is the total number of values in
** the P3 record (the P3 record is a prefix of the P1 record).
**
** See also: NotFound, MoveTo, IsUnique, NotExists
*/
/* Opcode: NotFound P1 P2 P3 * *
**
** Register P3 holds a blob constructed by MakeRecord. P1 is
** an index. If no entry exists in P1 that matches the blob then jump
** to P2. If an entry does existing, fall through. The cursor is left
** pointing to the entry that matches.
**
** See also: Found, MoveTo, NotExists, IsUnique
*/
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
int i = pOp->p1;
int alreadyExists = 0;
Cursor *pC;
assert( i>=0 && i<p->nCursor );
sqlite-amalgamation.c view on Meta::CPAN
pIn3->u.i = v;
assert( pIn3->flags&MEM_Int );
}
break;
}
/* Opcode: NotExists P1 P2 P3 * *
**
** Use the content of register P3 as a integer key. If a record
** with that key does not exist in table of P1, then jump to P2.
** If the record does exist, then fall thru. The cursor is left
** pointing to the record if it exists.
**
** The difference between this operation and NotFound is that this
** operation assumes the key is an integer and that P1 is a table whereas
** NotFound assumes key is a blob constructed from MakeRecord and
** P1 is an index.
**
** See also: Found, MoveTo, NotFound, IsUnique
*/
case OP_NotExists: { /* jump, in3 */
sqlite-amalgamation.c view on Meta::CPAN
/* res might be uninitialized if rc!=SQLITE_OK. But if rc!=SQLITE_OK
** processing is about to abort so we really do not care whether or not
** the following jump is taken. (In other words, do not stress over
** the error that valgrind sometimes shows on the next statement when
** running ioerr.test and similar failure-recovery test scripts.) */
if( res!=0 ){
pc = pOp->p2 - 1;
assert( pC->rowidIsValid==0 );
}
}else if( !pC->pseudoTable ){
/* This happens when an attempt to open a read cursor on the
** sqlite_master table returns SQLITE_EMPTY.
*/
assert( pC->isTable );
pc = pOp->p2 - 1;
assert( pC->rowidIsValid==0 );
}
break;
}
/* Opcode: Sequence P1 P2 * * *
**
** Find the next available sequence number for cursor P1.
** Write the sequence number into register P2.
** The sequence number on the cursor is incremented after this
** instruction.
*/
case OP_Sequence: { /* out2-prerelease */
int i = pOp->p1;
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
pOut->u.i = p->apCsr[i]->seqCount++;
MemSetTypeFlag(pOut, MEM_Int);
break;
}
/* Opcode: NewRowid P1 P2 P3 * *
**
** Get a new integer record number (a.k.a "rowid") used as the key to a table.
** The record number is not previously used as a key in the database
** table that cursor P1 points to. The new record number is written
** written to register P2.
**
** If P3>0 then P3 is a register that holds the largest previously
** generated record number. No new record numbers are allowed to be less
** than this value. When this value reaches its maximum, a SQLITE_FULL
** error is generated. The P3 register is updated with the generated
** record number. This P3 mechanism is used to help implement the
** AUTOINCREMENT feature.
*/
case OP_NewRowid: { /* out2-prerelease */
sqlite-amalgamation.c view on Meta::CPAN
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
}
MemSetTypeFlag(pOut, MEM_Int);
pOut->u.i = v;
break;
}
/* Opcode: Insert P1 P2 P3 P4 P5
**
** Write an entry into the table of cursor P1. A new entry is
** created if it doesn't already exist or the data for an existing
** entry is overwritten. The data is the value stored register
** number P2. The key is stored in register P3. The key must
** be an integer.
**
** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is
** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set,
** then rowid is stored for subsequent return by the
** sqlite3_last_insert_rowid() function (otherwise it is unmodified).
**
** Parameter P4 may point to a string containing the table-name, or
** may be NULL. If it is not NULL, then the update-hook
** (sqlite3.xUpdateCallback) is invoked following a successful insert.
**
** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
** allocated, then ownership of P2 is transferred to the pseudo-cursor
** and register P2 becomes ephemeral. If the cursor is changed, the
** value of register P2 will then change. Make sure this does not
** cause any problems.)
**
** This instruction only works on tables. The equivalent instruction
** for indices is OP_IdxInsert.
*/
case OP_Insert: {
Mem *pData = &p->aMem[pOp->p2];
Mem *pKey = &p->aMem[pOp->p3];
sqlite-amalgamation.c view on Meta::CPAN
int op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
assert( pC->isTable );
db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
assert( pC->iDb>=0 );
}
break;
}
/* Opcode: Delete P1 P2 * P4 *
**
** Delete the record at which the P1 cursor is currently pointing.
**
** The cursor will be left pointing at either the next or the previous
** record in the table. If it is left pointing at the next record, then
** the next Next instruction will be a no-op. Hence it is OK to delete
** a record from within an Next loop.
**
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not).
**
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
**
** If P4 is not NULL, then it is the name of the table that P1 is
** pointing to. The update hook will be invoked, if it exists.
** If P4 is not NULL then the P1 cursor must have been positioned
** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {
int i = pOp->p1;
i64 iKey;
Cursor *pC;
assert( i>=0 && i<p->nCursor );
pC = p->apCsr[i];
assert( pC!=0 );
sqlite-amalgamation.c view on Meta::CPAN
case OP_ResetCount: {
if( pOp->p1 ){
sqlite3VdbeSetChanges(db, p->nChange);
}
p->nChange = 0;
break;
}
/* Opcode: RowData P1 P2 * * *
**
** Write into register P2 the complete row data for cursor P1.
** There is no interpretation of the data.
** It is just copied onto the P2 register exactly as
** it is found in the database file.
**
** If the P1 cursor must be pointing to a valid row (not a NULL row)
** of a real table, not a pseudo-table.
*/
/* Opcode: RowKey P1 P2 * * *
**
** Write into register P2 the complete row key for cursor P1.
** There is no interpretation of the data.
** The key is copied onto the P3 register exactly as
** it is found in the database file.
**
** If the P1 cursor must be pointing to a valid row (not a NULL row)
** of a real table, not a pseudo-table.
*/
case OP_RowKey:
case OP_RowData: {
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
u32 n;
pOut = &p->aMem[pOp->p2];
sqlite-amalgamation.c view on Meta::CPAN
sqlite3BtreeKeySize(pC->pCursor, &v);
v = keyToInt(v);
}
pOut->u.i = v;
MemSetTypeFlag(pOut, MEM_Int);
break;
}
/* Opcode: NullRow P1 * * * *
**
** Move the cursor P1 to a null row. Any OP_Column operations
** that occur while the cursor is on the null row will always
** write a NULL.
*/
case OP_NullRow: {
int i = pOp->p1;
Cursor *pC;
assert( i>=0 && i<p->nCursor );
pC = p->apCsr[i];
assert( pC!=0 );
pC->nullRow = 1;
sqlite-amalgamation.c view on Meta::CPAN
pC->nullRow = res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
if( res ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: Next P1 P2 * * *
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index. If there are no more key/value pairs then fall through
** to the following instruction. But if the cursor advance was successful,
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.
**
** See also: Prev
*/
/* Opcode: Prev P1 P2 * * *
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index. If there is no previous key/value pairs then fall through
** to the following instruction. But if the cursor backup was successful,
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.
*/
case OP_Prev: /* jump */
case OP_Next: { /* jump */
Cursor *pC;
BtCursor *pCrsr;
int res;
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
sqlite-amalgamation.c view on Meta::CPAN
pC->cacheStatus = CACHE_STALE;
}
}
break;
}
/* Opcode: IdxDeleteM P1 P2 P3 * *
**
** The content of P3 registers starting at register P2 form
** an unpacked index key. This opcode removes that entry from the
** index opened by cursor P1.
*/
case OP_IdxDelete: {
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
assert( pOp->p3>0 );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
sqlite-amalgamation.c view on Meta::CPAN
}
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
}
break;
}
/* Opcode: IdxRowid P1 P2 * * *
**
** Write into register P2 an integer which is the last entry in the record at
** the end of the index key pointed to by cursor P1. This integer should be
** the rowid of the table entry to which this index entry points.
**
** See also: Rowid, MakeIdxRec.
*/
case OP_IdxRowid: { /* out2-prerelease */
int i = pOp->p1;
BtCursor *pCrsr;
Cursor *pC;
assert( i>=0 && i<p->nCursor );
sqlite-amalgamation.c view on Meta::CPAN
**
** The P4 register values beginning with P3 form an unpacked index
** key that omits the ROWID. Compare this key value against the index
** that P1 is currently pointing to, ignoring the ROWID on the P1 index.
**
** If the P1 index entry is greater than or equal to the key value
** then jump to P2. Otherwise fall through to the next instruction.
**
** If P5 is non-zero then the key value is increased by an epsilon
** prior to the comparison. This make the opcode work like IdxGT except
** that if the key from register P3 is a prefix of the key in the cursor,
** the result is false whereas it would be true with IdxGT.
*/
/* Opcode: IdxLT P1 P2 P3 * P5
**
** The P4 register values beginning with P3 form an unpacked index
** key that omits the ROWID. Compare this key value against the index
** that P1 is currently pointing to, ignoring the ROWID on the P1 index.
**
** If the P1 index entry is less than the key value then jump to P2.
** Otherwise fall through to the next instruction.
sqlite-amalgamation.c view on Meta::CPAN
rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
p->inVtabMethod = 0;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VOpen P1 * * P4 *
**
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
** P1 is a cursor number. This opcode opens a cursor to the virtual
** table and stores that cursor in P1.
*/
case OP_VOpen: {
Cursor *pCur = 0;
sqlite3_vtab_cursor *pVtabCursor = 0;
sqlite3_vtab *pVtab = pOp->p4.pVtab;
sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;
assert(pVtab && pModule);
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = pModule->xOpen(pVtab, &pVtabCursor);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */
pVtabCursor->pVtab = pVtab;
/* Initialise vdbe cursor object */
pCur = allocateCursor(p, pOp->p1, &pOp[-1], -1, 0);
if( pCur ){
pCur->pVtabCursor = pVtabCursor;
pCur->pModule = pVtabCursor->pVtab->pModule;
}else{
db->mallocFailed = 1;
pModule->xClose(pVtabCursor);
}
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VFilter P1 P2 P3 P4 *
**
** P1 is a cursor opened using VOpen. P2 is an address to jump to if
** the filtered result set is empty.
**
** P4 is either NULL or a string that was generated by the xBestIndex
** method of the module. The interpretation of the P4 string is left
** to the module implementation.
**
** This opcode invokes the xFilter method on the virtual table specified
** by P1. The integer query plan parameter to xFilter is stored in register
** P3. Register P3+1 stores the argc parameter to be passed to the
** xFilter method. Registers P3+2..P3+1+argc are the argc
sqlite-amalgamation.c view on Meta::CPAN
** xFilter as argv. Register P3+2 becomes argv[0] when passed to xFilter.
**
** A jump is made to P2 if the result set after filtering would be empty.
*/
case OP_VFilter: { /* jump */
int nArg;
int iQuery;
const sqlite3_module *pModule;
Mem *pQuery = &p->aMem[pOp->p3];
Mem *pArgc = &pQuery[1];
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
Cursor *pCur = p->apCsr[pOp->p1];
REGISTER_TRACE(pOp->p3, pQuery);
assert( pCur->pVtabCursor );
pVtabCursor = pCur->pVtabCursor;
pVtab = pVtabCursor->pVtab;
pModule = pVtab->pModule;
sqlite-amalgamation.c view on Meta::CPAN
pCur->nullRow = 0;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VRowid P1 P2 * * *
**
** Store into register P2 the rowid of
** the virtual-table that the P1 cursor is pointing to.
*/
case OP_VRowid: { /* out2-prerelease */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
sqlite_int64 iRow;
Cursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
if( pCur->nullRow ){
break;
sqlite-amalgamation.c view on Meta::CPAN
pOut->u.i = iRow;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VColumn P1 P2 P3 * *
**
** Store the value of the P2-th column of
** the row of the virtual-table that the
** P1 cursor is pointing to into register P3.
*/
case OP_VColumn: {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
Cursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
sqlite-amalgamation.c view on Meta::CPAN
break;
}
pVtab = pCur->pVtabCursor->pVtab;
pModule = pVtab->pModule;
assert( pModule->xNext );
/* Invoke the xNext() method of the module. There is no way for the
** underlying implementation to return an error if one occurs during
** xNext(). Instead, if an error occurs, true is returned (indicating that
** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor.
*/
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
sqlite3VtabLock(pVtab);
p->inVtabMethod = 1;
rc = pModule->xNext(pCur->pVtabCursor);
p->inVtabMethod = 0;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
sqlite3VtabUnlock(db, pVtab);
sqlite-amalgamation.c view on Meta::CPAN
#ifndef SQLITE_OMIT_INCRBLOB
/*
** Valid sqlite3_blob* handles point to Incrblob structures.
*/
typedef struct Incrblob Incrblob;
struct Incrblob {
int flags; /* Copy of "flags" passed to sqlite3_blob_open() */
int nByte; /* Size of open blob, in bytes */
int iOffset; /* Byte offset of blob in cursor data */
BtCursor *pCsr; /* Cursor pointing at blob row */
sqlite3_stmt *pStmt; /* Statement holding cursor open */
sqlite3 *db; /* The associated database */
};
/*
** Open a blob handle.
*/
SQLITE_API int sqlite3_blob_open(
sqlite3* db, /* The database connection */
const char *zDb, /* The attached database containing the blob */
const char *zTable, /* The table containing the blob */
const char *zColumn, /* The column containing the blob */
sqlite_int64 iRow, /* The row containing the glob */
int flags, /* True -> read/write access, false -> read-only */
sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
){
int nAttempt = 0;
int iCol; /* Index of zColumn in row-record */
/* This VDBE program seeks a btree cursor to the identified
** db/table/row entry. The reason for using a vdbe program instead
** of writing code to use the b-tree layer directly is that the
** vdbe program will take advantage of the various transaction,
** locking and error handling infrastructure built into the vdbe.
**
** After seeking the cursor, the vdbe executes an OP_ResultRow.
** Code external to the Vdbe then "borrows" the b-tree cursor and
** uses it to implement the blob_read(), blob_write() and
** blob_bytes() functions.
**
** The sqlite3_blob_close() function finalizes the vdbe program,
** which closes the b-tree cursor and (possibly) commits the
** transaction.
*/
static const VdbeOpList openBlob[] = {
{OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
{OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
/* One of the following two instructions is replaced by an
** OP_Noop before exection.
*/
{OP_SetNumColumns, 0, 0, 0}, /* 2: Num cols for cursor */
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
{OP_SetNumColumns, 0, 0, 0}, /* 4: Num cols for cursor */
{OP_OpenWrite, 0, 0, 0}, /* 5: Open cursor 0 for read/write */
{OP_Variable, 1, 1, 0}, /* 6: Push the rowid to the stack */
{OP_NotExists, 0, 10, 1}, /* 7: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 8 */
{OP_ResultRow, 1, 0, 0}, /* 9 */
{OP_Close, 0, 0, 0}, /* 10 */
{OP_Halt, 0, 0, 0}, /* 11 */
};
Vdbe *v = 0;
int rc = SQLITE_OK;
char zErr[128];
sqlite-amalgamation.c view on Meta::CPAN
/* Make sure a mutex is held on the table to be accessed */
sqlite3VdbeUsesBtree(v, iDb);
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum.
*/
sqlite3VdbeChangeToNoop(v, (flags ? 3 : 5), 1);
sqlite3VdbeChangeP2(v, (flags ? 5 : 3), pTab->tnum);
sqlite3VdbeChangeP3(v, (flags ? 5 : 3), iDb);
/* Configure the OP_SetNumColumns. Configure the cursor to
** think that the table has one more column than it really
** does. An OP_Column to retrieve this imaginary column will
** always return an SQL NULL. This is useful because it means
** we can invoke OP_Column to fill in the vdbe cursors type
** and offset cache without causing any IO.
*/
sqlite3VdbeChangeP2(v, flags ? 4 : 2, pTab->nCol+1);
sqlite3VdbeChangeP2(v, 8, pTab->nCol);
if( !db->mallocFailed ){
sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
}
}
sqlite3BtreeLeaveAll(db);
sqlite-amalgamation.c view on Meta::CPAN
|| db->mallocFailed );
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pItem->sortOrder = pOldItem->sortOrder;
pItem->isAgg = pOldItem->isAgg;
pItem->done = 0;
}
return pNew;
}
/*
** If cursors, triggers, views and subqueries are all omitted from
** the build, then none of the following routines, except for
** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
** called with a NULL argument.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|| !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
SrcList *pNew;
int i;
int nByte;
sqlite-amalgamation.c view on Meta::CPAN
}
/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
** that name in the set of source tables in pSrcList and make the pExpr
** expression node refer back to that source column. The following changes
** are made to pExpr:
**
** pExpr->iDb Set the index in db->aDb[] of the database holding
** the table.
** pExpr->iTable Set to the cursor number for the table obtained
** from pSrcList.
** pExpr->iColumn Set to the column number within the table.
** pExpr->op Set to TK_COLUMN.
** pExpr->pLeft Any expression this points to is deleted
** pExpr->pRight Any expression this points to is deleted.
**
** The pDbToken is the name of the database (the "X"). This value may be
** NULL meaning that name is of the form Y.Z or Z. Any available database
** can be used. The pTableToken is the name of the table (the "Y"). This
** value can be NULL if pDbToken is also NULL. If pTableToken is NULL it
sqlite-amalgamation.c view on Meta::CPAN
return 0;
}
/*
** This routine walks an expression tree and resolves references to
** table columns. Nodes of the form ID.ID or ID resolve into an
** index to the table in the table list and a column offset. The
** Expr.opcode for such nodes is changed to TK_COLUMN. The Expr.iTable
** value is changed to the index of the referenced table in pTabList
** plus the "base" value. The base value will ultimately become the
** VDBE cursor number for a cursor that is pointing into the referenced
** table. The Expr.iColumn value is changed to the index of the column
** of the referenced table. The Expr.iColumn value for the special
** ROWID column is -1. Any INTEGER PRIMARY KEY column is tried as an
** alias for ROWID.
**
** Also resolve function names and check the functions for proper
** usage. Make sure all function names are recognized and all functions
** have the correct number of arguments. Leave an error message
** in pParse->zErrMsg if anything is amiss. Return the number of errors.
**
sqlite-amalgamation.c view on Meta::CPAN
return 1;
}
#endif /* SQLITE_OMIT_SUBQUERY */
/*
** This function is used by the implementation of the IN (...) operator.
** It's job is to find or create a b-tree structure that may be used
** either to test for membership of the (...) set or to iterate through
** its members, skipping duplicates.
**
** The cursor opened on the structure (database table, database index
** or ephermal table) is stored in pX->iTable before this function returns.
** The returned value indicates the structure type, as follows:
**
** IN_INDEX_ROWID - The cursor was opened on a database table.
** IN_INDEX_INDEX - The cursor was opened on a database index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
** populated epheremal table.
**
** An existing structure may only be used if the SELECT is of the simple
** form:
**
** SELECT <column> FROM <table>
**
** If prNotFound parameter is 0, then the structure will be used to iterate
** through the set members, skipping any duplicates. In this case an
** epheremal table must be used unless the selected <column> is guaranteed
sqlite-amalgamation.c view on Meta::CPAN
}
}
/*
** Generate code that will extract the iColumn-th column from
** table pTab and store the column value in a register. An effort
** is made to store the column value in register iReg, but this is
** not guaranteed. The location of the column value is returned.
**
** There must be an open cursor to pTab in iTable when this routine
** is called. If iColumn<0 then code is generated that extracts the rowid.
**
** This routine might attempt to reuse the value of the column that
** has already been loaded into a register. The value will always
** be used if it has not undergone any affinity changes. But if
** an affinity change has occurred, then the cached value will only be
** used if allowAffChng is true.
*/
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
Parse *pParse, /* Parsing and code generating context */
Table *pTab, /* Description of the table we are reading from */
int iColumn, /* Index of the table column */
int iTable, /* The cursor pointing to the table */
int iReg, /* Store results here */
int allowAffChng /* True if prior affinity changes are OK */
){
Vdbe *v = pParse->pVdbe;
int i;
struct yColCache *p;
for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
if( p->iTable==iTable && p->iColumn==iColumn
&& (!p->affChange || allowAffChng) ){
sqlite-amalgamation.c view on Meta::CPAN
i++;
if( i>=ArraySize(pParse->aColCache) ) i = 0;
if( i>pParse->nColCache ) pParse->nColCache = i;
pParse->iColCache = i;
}
return iReg;
}
/*
** Clear all column cache entries associated with the vdbe
** cursor with cursor number iTable.
*/
SQLITE_PRIVATE void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){
if( iTable<0 ){
pParse->nColCache = 0;
pParse->iColCache = 0;
}else{
int i;
for(i=0; i<pParse->nColCache; i++){
if( pParse->aColCache[i].iTable==iTable ){
testcase( i==pParse->nColCache-1 );
sqlite-amalgamation.c view on Meta::CPAN
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code associated with the ANALYZE command.
**
** @(#) $Id: analyze.c,v 1.43 2008/07/28 19:34:53 drh Exp $
*/
#ifndef SQLITE_OMIT_ANALYZE
/*
** This routine generates code that opens the sqlite_stat1 table on cursor
** iStatCur.
**
** If the sqlite_stat1 tables does not previously exist, it is created.
** If it does previously exist, all entires associated with table zWhere
** are removed. If zWhere==0 then all entries are removed.
*/
static void openStatTable(
Parse *pParse, /* Parsing context */
int iDb, /* The database we are looking in */
int iStatCur, /* Open the sqlite_stat1 table on this cursor */
const char *zWhere /* Delete entries associated with this table */
){
sqlite3 *db = pParse->db;
Db *pDb;
int iRootPage;
int createStat1 = 0;
Table *pStat;
Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
sqlite-amalgamation.c view on Meta::CPAN
iIdxCur = pParse->nTab;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
int regFields; /* Register block for building records */
int regRec; /* Register holding completed record */
int regTemp; /* Temporary use register */
int regCol; /* Content of a column from the table being analyzed */
int regRowid; /* Rowid for the inserted record */
int regF2;
/* Open a cursor to the index to be analyzed
*/
assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) );
nCol = pIdx->nColumn;
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nCol+1);
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb,
(char *)pKey, P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
regFields = iMem+nCol*2;
regTemp = regRowid = regCol = regFields+3;
regRec = regCol+1;
sqlite-amalgamation.c view on Meta::CPAN
zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n);
sqlite3Dequote(zName);
}else{
zName = 0;
}
return zName;
}
/*
** Open the sqlite_master table stored in database number iDb for
** writing. The table is opened using cursor 0.
*/
SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){
Vdbe *v = sqlite3GetVdbe(p);
sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5);/* sqlite_master has 5 columns */
sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
}
/*
** The token *pName contains the name of a database (either "main" or
sqlite-amalgamation.c view on Meta::CPAN
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** The Table structure pTable is really a VIEW. Fill in the names of
** the columns of the view in the pTable structure. Return the number
** of errors. If an error is seen leave an error message in pParse->zErrMsg.
*/
SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
assert( pTable );
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( sqlite3VtabCallConnect(pParse, pTable) ){
return SQLITE_ERROR;
}
if( IsVirtual(pTable) ) return 0;
sqlite-amalgamation.c view on Meta::CPAN
** should always fail. But we will leave it in place just to be safe.
*/
if( pTable->nCol<0 ){
sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
return 1;
}
assert( pTable->nCol>=0 );
/* If we get this far, it means we need to compute the table names.
** Note that the call to sqlite3ResultSetOfSelect() will expand any
** "*" elements in the results set of the view and will assign cursors
** to the elements of the FROM clause. But we do not want these changes
** to be permanent. So the computation is done on a copy of the SELECT
** statement that defines the view.
*/
assert( pTable->pSelect );
pSel = sqlite3SelectDup(db, pTable->pSelect);
if( pSel ){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
sqlite-amalgamation.c view on Meta::CPAN
** content of an index in response to a REINDEX command.
**
** if memRootPage is not negative, it means that the index is newly
** created. The register specified by memRootPage contains the
** root page number of the index. If memRootPage is negative, then
** the index already exists and must be cleared before being refilled and
** the root page number of the index is taken from pIndex->tnum.
*/
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
Table *pTab = pIndex->pTable; /* The table that is indexed */
int iTab = pParse->nTab; /* Btree cursor used for pTab */
int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */
int addr1; /* Address of top of loop */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
KeyInfo *pKey; /* KeyInfo for index */
int regIdxKey; /* Registers containing the index key */
int regRecord; /* Register holding assemblied index record */
sqlite3 *db = pParse->db; /* The database connection */
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
sqlite-amalgamation.c view on Meta::CPAN
}
pItem->zName = sqlite3NameFromToken(db, pTable);
pItem->zDatabase = sqlite3NameFromToken(db, pDatabase);
pItem->iCursor = -1;
pItem->isPopulated = 0;
pList->nSrc++;
return pList;
}
/*
** Assign cursors to all tables in a SrcList
*/
SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
int i;
struct SrcList_item *pItem;
assert(pList || pParse->db->mallocFailed );
if( pList ){
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->iCursor>=0 ) break;
pItem->iCursor = pParse->nTab++;
if( pItem->pSelect ){
sqlite-amalgamation.c view on Meta::CPAN
}
#endif
return 0;
}
/*
** Generate code that will open a table for reading.
*/
SQLITE_PRIVATE void sqlite3OpenTable(
Parse *p, /* Generate code into this VDBE */
int iCur, /* The cursor number of the table */
int iDb, /* The database index in sqlite3.aDb[] */
Table *pTab, /* The table to be opened */
int opcode /* OP_OpenRead or OP_OpenWrite */
){
Vdbe *v;
if( IsVirtual(pTab) ) return;
v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite-amalgamation.c view on Meta::CPAN
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
goto delete_from_cleanup;
}
/* If pTab is really a view, make sure it has been initialized.
*/
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto delete_from_cleanup;
}
/* Allocate a cursor used to store the old.* data for a trigger.
*/
if( triggers_exist ){
oldIdx = pParse->nTab++;
}
/* Assign cursor number to the table and all its indices.
*/
assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
pParse->nTab++;
}
/* Start the view context
*/
if( isView ){
sqlite-amalgamation.c view on Meta::CPAN
sqlite3VdbeAddOp1(v, OP_OpenPseudo, oldIdx);
}
/* Delete every item whose key was written to the list during the
** database scan. We have to delete items after the scan is complete
** because deleting an item can change the scan order.
*/
end = sqlite3VdbeMakeLabel(v);
if( !isView ){
/* Open cursors for the table we are deleting from and
** all its indices.
*/
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
}
/* This is the beginning of the delete loop. If a trigger encounters
** an IGNORE constraint, it jumps back to here.
*/
if( triggers_exist ){
sqlite3VdbeResolveLabel(v, addr);
sqlite-amalgamation.c view on Meta::CPAN
const char *pVtab = (const char *)pTab->pVtab;
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVtab, P4_VTAB);
}else
#endif
{
sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0);
}
}
/* If there are row triggers, close all cursors then invoke
** the AFTER triggers
*/
if( triggers_exist ){
/* Jump back and run the AFTER triggers */
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
/* End of the delete loop */
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */
if( !isView && !IsVirtual(pTab) ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx->tnum);
}
sqlite3VdbeAddOp1(v, OP_Close, iCur);
}
}
/*
** Return the number of rows that were deleted. If this routine is
sqlite-amalgamation.c view on Meta::CPAN
return;
}
/*
** This routine generates VDBE code that causes a single row of a
** single table to be deleted.
**
** The VDBE must be in a particular state when this routine is called.
** These are the requirements:
**
** 1. A read/write cursor pointing to pTab, the table containing the row
** to be deleted, must be opened as cursor number "base".
**
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number base+i for the i-th index.
**
** 3. The record number of the row to be deleted must be stored in
** memory cell iRowid.
**
** This routine pops the top of the stack to remove the record number
** and then generates code to remove both the table record and all index
** entries that point to that record.
*/
SQLITE_PRIVATE void sqlite3GenerateRowDelete(
Parse *pParse, /* Parsing context */
sqlite-amalgamation.c view on Meta::CPAN
sqlite3VdbeJumpHere(v, addr);
}
/*
** This routine generates VDBE code that causes the deletion of all
** index entries associated with a single row of a single table.
**
** The VDBE must be in a particular state when this routine is called.
** These are the requirements:
**
** 1. A read/write cursor pointing to pTab, the table containing the row
** to be deleted, must be opened as cursor number "iCur".
**
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number iCur+i for the i-th index.
**
** 3. The "iCur" cursor must be pointing to the row that is to be
** deleted.
*/
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
Parse *pParse, /* Parsing and code generating context */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
){
int i;
Index *pIdx;
sqlite-amalgamation.c view on Meta::CPAN
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 0);
sqlite3VdbeAddOp3(pParse->pVdbe, OP_IdxDelete, iCur+i, r1,pIdx->nColumn+1);
}
}
/*
** Generate code that will assemble an index key and put it in register
** regOut. The key with be for index pIdx which is an index on pTab.
** iCur is the index of a cursor open on the pTab table and pointing to
** the entry that needs indexing.
**
** Return a register number which is the first in a block of
** registers that holds the elements of the index key. The
** block of registers has already been deallocated by the time
** this routine returns.
*/
SQLITE_PRIVATE int sqlite3GenerateIndexKey(
Parse *pParse, /* Parsing context */
Index *pIdx, /* The index for which to generate a key */
sqlite-amalgamation.c view on Meta::CPAN
** The pList parameter holds EXPRLIST in the first form of the INSERT
** statement above, and pSelect is NULL. For the second form, pList is
** NULL and pSelect is a pointer to the select statement used to generate
** data for the insert.
**
** The code generated follows one of four templates. For a simple
** select with data coming from a VALUES clause, the code executes
** once straight down through. Pseudo-code follows (we call this
** the "1st template"):
**
** open write cursor to <table> and its indices
** puts VALUES clause expressions onto the stack
** write the resulting record into <table>
** cleanup
**
** The three remaining templates assume the statement is of the form
**
** INSERT INTO <table> SELECT ...
**
** If the SELECT clause is of the restricted form "SELECT * FROM <table2>" -
** in other words if the SELECT pulls all columns from a single table
** and there is no WHERE or LIMIT or GROUP BY or ORDER BY clauses, and
** if <table2> and <table1> are distinct tables but have identical
** schemas, including all the same indices, then a special optimization
** is invoked that copies raw records from <table2> over to <table1>.
** See the xferOptimization() function for the implementation of this
** template. This is the 2nd template.
**
** open a write cursor to <table>
** open read cursor on <table2>
** transfer all records in <table2> over to <table>
** close cursors
** foreach index on <table>
** open a write cursor on the <table> index
** open a read cursor on the corresponding <table2> index
** transfer all records from the read to the write cursors
** close cursors
** end foreach
**
** The 3rd template is for when the second template does not apply
** and the SELECT clause does not read from <table> at any time.
** The generated code follows this template:
**
** EOF <- 0
** X <- A
** goto B
** A: setup for the SELECT
** loop over the rows in the SELECT
** load values into registers R..R+n
** yield X
** end loop
** cleanup after the SELECT
** EOF <- 1
** yield X
** goto A
** B: open write cursor to <table> and its indices
** C: yield X
** if EOF goto D
** insert the select result into <table> from R..R+n
** goto C
** D: cleanup
**
** The 4th template is used if the insert statement takes its
** values from a SELECT but the data is being inserted into a table
** that is also read as part of the SELECT. In the third form,
** we have to use a intermediate table to store the results of
sqlite-amalgamation.c view on Meta::CPAN
** end loop
** cleanup after the SELECT
** EOF <- 1
** yield X
** halt-error
** B: open temp table
** L: yield X
** if EOF goto M
** insert row from R..R+n into temp table
** goto L
** M: open write cursor to <table> and its indices
** rewind temp table
** C: loop over rows of intermediate table
** transfer values form intermediate table into <table>
** end loop
** D: cleanup
*/
SQLITE_PRIVATE void sqlite3Insert(
Parse *pParse, /* Parser context */
SrcList *pTabList, /* Name of table into which we are inserting */
ExprList *pList, /* List of values to be inserted */
sqlite-amalgamation.c view on Meta::CPAN
const char *zDb; /* Name of the database holding this table */
int i, j, idx; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */
int nColumn; /* Number of columns in the data */
int nHidden = 0; /* Number of hidden columns if TABLE is virtual */
int baseCur = 0; /* VDBE Cursor number for pTab */
int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
int endOfLoop; /* Label for the end of the insertion loop */
int useTempTable = 0; /* Store SELECT results in intermediate table */
int srcTab = 0; /* Data comes from this temporary cursor if >=0 */
int addrInsTop = 0; /* Jump to label "D" */
int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */
int addrSelect = 0; /* Address of coroutine that implements the SELECT */
SelectDest dest; /* Destination for SELECT on rhs of INSERT */
int newIdx = -1; /* Cursor for the NEW pseudo-table */
int iDb; /* Index of database holding TABLE */
Db *pDb; /* The database containing table being inserted into */
int appendFlag = 0; /* True if the insert is likely to be an append */
/* Register allocations */
sqlite-amalgamation.c view on Meta::CPAN
** UNIQUE REPLACE The other row that conflicts with the row
** being inserted is removed.
**
** CHECK REPLACE Illegal. The results in an exception.
**
** Which action to take is determined by the overrideError parameter.
** Or if overrideError==OE_Default, then the pParse->onError parameter
** is used. Or if pParse->onError==OE_Default then the onError value
** for the constraint is used.
**
** The calling routine must open a read/write cursor for pTab with
** cursor number "baseCur". All indices of pTab must also have open
** read/write cursors with cursor number baseCur+i for the i-th cursor.
** Except, if there is no possibility of a REPLACE action then
** cursors do not need to be open for indices where aRegIdx[i]==0.
*/
SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
Parse *pParse, /* The parser context */
Table *pTab, /* the table into which we are inserting */
int baseCur, /* Index of a read/write cursor pointing at pTab */
int regRowid, /* Index of the range of input registers */
int *aRegIdx, /* Register used by each index. 0 for unused indices */
int rowidChng, /* True if the rowid might collide with existing entry */
int isUpdate, /* True for UPDATE, False for INSERT */
int overrideError, /* Override onError to this if not OE_Default */
int ignoreDest /* Jump to this label on an OE_Ignore resolution */
){
int i;
Vdbe *v;
int nCol;
sqlite-amalgamation.c view on Meta::CPAN
** that was started by a prior call to sqlite3GenerateConstraintChecks.
** A consecutive range of registers starting at regRowid contains the
** rowid and the content to be inserted.
**
** The arguments to this routine should be the same as the first six
** arguments to sqlite3GenerateConstraintChecks.
*/
SQLITE_PRIVATE void sqlite3CompleteInsertion(
Parse *pParse, /* The parser context */
Table *pTab, /* the table into which we are inserting */
int baseCur, /* Index of a read/write cursor pointing at pTab */
int regRowid, /* Range of content */
int *aRegIdx, /* Register used by each index. 0 for unused indices */
int rowidChng, /* True if the record number will change */
int isUpdate, /* True for UPDATE, False for INSERT */
int newIdx, /* Index of NEW table for triggers. -1 if none */
int appendBias /* True if this is likely to be an append */
){
int i;
Vdbe *v;
int nIdx;
sqlite-amalgamation.c view on Meta::CPAN
pik_flags |= OPFLAG_APPEND;
}
sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
if( !pParse->nested ){
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
}
sqlite3VdbeChangeP5(v, pik_flags);
}
/*
** Generate code that will open cursors for a table and for all
** indices of that table. The "baseCur" parameter is the cursor number used
** for the table. Indices are opened on subsequent cursors.
**
** Return the number of indices on the table.
*/
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
Parse *pParse, /* Parsing context */
Table *pTab, /* Table to be opened */
int baseCur, /* Cursor number assigned to the table */
int op /* OP_OpenRead or OP_OpenWrite */
){
int i;
sqlite-amalgamation.c view on Meta::CPAN
(void)sqlite3SafetyOn(db);
if( rc ){
rc = initData.rc;
goto error_out;
}
pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
if( pTab ){
pTab->readOnly = 1;
}
/* Create a cursor to hold the database open
*/
pDb = &db->aDb[iDb];
if( pDb->pBt==0 ){
if( !OMIT_TEMPDB && iDb==1 ){
DbSetProperty(db, 1, DB_SchemaLoaded);
}
return SQLITE_OK;
}
curMain = sqlite3MallocZero(sqlite3BtreeCursorSize());
if( !curMain ){
sqlite-amalgamation.c view on Meta::CPAN
** Add a term to the WHERE expression in *ppExpr that requires the
** zCol column to be equal in the two tables pTab1 and pTab2.
*/
static void addWhereTerm(
Parse *pParse, /* Parsing context */
const char *zCol, /* Name of the column */
const Table *pTab1, /* First table */
const char *zAlias1, /* Alias for first table. May be NULL */
const Table *pTab2, /* Second table */
const char *zAlias2, /* Alias for second table. May be NULL */
int iRightJoinTable, /* VDBE cursor for the right table */
Expr **ppExpr, /* Add the equality term to this expression */
int isOuterJoin /* True if dealing with an OUTER join */
){
Expr *pE1a, *pE1b, *pE1c;
Expr *pE2a, *pE2b, *pE2c;
Expr *pE;
pE1a = sqlite3CreateIdExpr(pParse, zCol);
pE2a = sqlite3CreateIdExpr(pParse, zCol);
if( zAlias1==0 ){
sqlite-amalgamation.c view on Meta::CPAN
sqlite3DeleteTable(pTab);
return 0;
}
return pTab;
}
/*
** Prepare a SELECT statement for processing by doing the following
** things:
**
** (1) Make sure VDBE cursor numbers have been assigned to every
** element of the FROM clause.
**
** (2) Fill in the pTabList->a[].pTab fields in the SrcList that
** defines FROM clause. When views appear in the FROM clause,
** fill pTabList->a[].pSelect with a copy of the SELECT statement
** that implements the view. A copy is made of the view's SELECT
** statement so that we can freely modify or delete that statement
** without worrying about messing up the presistent representation
** of the view.
**
sqlite-amalgamation.c view on Meta::CPAN
ExprList *pEList;
struct SrcList_item *pFrom;
sqlite3 *db = pParse->db;
if( p==0 || p->pSrc==0 || db->mallocFailed ){
return 1;
}
pTabList = p->pSrc;
pEList = p->pEList;
/* Make sure cursor numbers have been assigned to all entries in
** the FROM clause of the SELECT statement.
*/
sqlite3SrcListAssignCursors(pParse, p->pSrc);
/* Look up every table named in the FROM clause of the select. If
** an entry of the FROM clause is a subquery instead of a table or view,
** then create a transient table structure to describe the subquery.
*/
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab;
sqlite-amalgamation.c view on Meta::CPAN
generateColumnNames(pParse, 0, pFirst->pEList);
}
/* Reassembly the compound query so that it will be freed correctly
** by the calling function */
if( p->pPrior ){
sqlite3SelectDelete(db, p->pPrior);
}
p->pPrior = pPrior;
/*** TBD: Insert subroutine calls to close cursors on incomplete
**** subqueries ****/
return SQLITE_OK;
}
#endif
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/* Forward Declarations */
static void substExprList(sqlite3*, ExprList*, int, ExprList*);
static void substSelect(sqlite3*, Select *, int, ExprList *);
/*
** Scan through the expression pExpr. Replace every reference to
** a column in table number iTable with a copy of the iColumn-th
** entry in pEList. (But leave references to the ROWID column
** unchanged.)
**
** This routine is part of the flattening procedure. A subquery
** whose result set is defined by pEList appears as entry in the
** FROM clause of a SELECT such that the VDBE cursor assigned to that
** FORM clause entry is iTable. This routine make the necessary
** changes to pExpr so that it refers directly to the source table
** of the subquery rather the result set of the subquery.
*/
static void substExpr(
sqlite3 *db, /* Report malloc errors to this connection */
Expr *pExpr, /* Expr in which substitution occurs */
int iTable, /* Table to be substituted */
ExprList *pEList /* Substitute expressions */
){
sqlite-amalgamation.c view on Meta::CPAN
int isAgg, /* True if outer SELECT uses aggregate functions */
int subqueryIsAgg /* True if the subquery uses aggregate functions */
){
const char *zSavedAuthContext = pParse->zAuthContext;
Select *pParent;
Select *pSub; /* The inner query or "subquery" */
Select *pSub1; /* Pointer to the rightmost select in sub-query */
SrcList *pSrc; /* The FROM clause of the outer query */
SrcList *pSubSrc; /* The FROM clause of the subquery */
ExprList *pList; /* The result set of the outer query */
int iParent; /* VDBE cursor number of the pSub result set temp table */
int i; /* Loop counter */
Expr *pWhere; /* The WHERE clause */
struct SrcList_item *pSubitem; /* The subquery */
sqlite3 *db = pParse->db;
/* Check to see if flattening is permitted. Return 0 if not.
*/
if( p==0 ) return 0;
pSrc = p->pSrc;
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
sqlite-amalgamation.c view on Meta::CPAN
*/
pSub = pSub1 = pSubitem->pSelect;
for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){
int nSubSrc = pSubSrc->nSrc;
int jointype = 0;
pSubSrc = pSub->pSrc;
pSrc = pParent->pSrc;
/* Move all of the FROM elements of the subquery into the
** the FROM clause of the outer query. Before doing this, remember
** the cursor number for the original outer query FROM element in
** iParent. The iParent cursor will never be used. Subsequent code
** will scan expressions looking for iParent references and replace
** those references with expressions that resolve to the subquery FROM
** elements we are now copying in.
*/
if( pSrc ){
pSubitem = &pSrc->a[iFrom];
nSubSrc = pSubSrc->nSrc;
jointype = pSubitem->jointype;
sqlite3DeleteTable(pSubitem->pTab);
sqlite3DbFree(db, pSubitem->zDatabase);
sqlite-amalgamation.c view on Meta::CPAN
assert( !pOuterNC );
return SQLITE_OK;
}
p->isResolved = 1;
/* If there have already been errors, do nothing. */
if( pParse->nErr>0 ){
return SQLITE_ERROR;
}
/* Prepare the select statement. This call will allocate all cursors
** required to handle the tables and subqueries in the FROM clause.
*/
if( prepSelectStmt(pParse, p) ){
return SQLITE_ERROR;
}
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
** are not allowed to refer to any names, so pass an empty NameContext.
*/
memset(&sNC, 0, sizeof(sNC));
sqlite-amalgamation.c view on Meta::CPAN
struct AggInfo_func *pF;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
ExprList *pList = pF->pExpr->pList;
sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
(void*)pF->pFunc, P4_FUNCDEF);
}
}
/*
** Update the accumulator memory cells for an aggregate based on
** the current cursor position.
*/
static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
Vdbe *v = pParse->pVdbe;
int i;
struct AggInfo_func *pF;
struct AggInfo_col *pC;
pAggInfo->directMode = 1;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
int nArg;
sqlite-amalgamation.c view on Meta::CPAN
** SRT_Set Store results as keys of table pDest->iParm.
** Apply the affinity pDest->affinity before storing them.
**
** SRT_Union Store results as a key in a temporary table pDest->iParm.
**
** SRT_Except Remove results from the temporary table pDest->iParm.
**
** SRT_Table Store results in temporary table pDest->iParm
**
** SRT_EphemTab Create an temporary table pDest->iParm and store
** the result there. The cursor is left open after
** returning.
**
** SRT_Coroutine Invoke a co-routine to compute a single row of
** the result
**
** SRT_Exists Store a 1 in memory cell pDest->iParm if the result
** set is not empty.
**
** SRT_Discard Throw the results away.
**
sqlite-amalgamation.c view on Meta::CPAN
return 0;
}
/*
** This is called to code FOR EACH ROW triggers.
**
** When the code that this function generates is executed, the following
** must be true:
**
** 1. No cursors may be open in the main database. (But newIdx and oldIdx
** can be indices of cursors in temporary tables. See below.)
**
** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
** a temporary vdbe cursor (index newIdx) must be open and pointing at
** a row containing values to be substituted for new.* expressions in the
** trigger program(s).
**
** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
** a temporary vdbe cursor (index oldIdx) must be open and pointing at
** a row containing values to be substituted for old.* expressions in the
** trigger program(s).
**
** If they are not NULL, the piOldColMask and piNewColMask output variables
** are set to values that describe the columns used by the trigger program
** in the OLD.* and NEW.* tables respectively. If column N of the
** pseudo-table is read at least once, the corresponding bit of the output
** mask is set. If a column with an index greater than 32 is read, the
** output mask is set to the special value 0xffffffff.
**
sqlite-amalgamation.c view on Meta::CPAN
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto update_cleanup;
}
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol );
if( aXRef==0 ) goto update_cleanup;
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
/* If there are FOR EACH ROW triggers, allocate cursors for the
** special OLD and NEW tables
*/
if( triggers_exist ){
newIdx = pParse->nTab++;
oldIdx = pParse->nTab++;
}
/* Allocate a cursors for the main database table and for all indices.
** The index cursors might not be used, but if they are used they
** need to occur right after the database cursor. So go ahead and
** allocate enough space, just in case.
*/
pTabList->a[0].iCursor = iCur = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
pParse->nTab++;
}
/* Initialize the name-context */
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sqlite-amalgamation.c view on Meta::CPAN
sqlite3VdbeJumpHere(v, a1);
}else{
addr = sqlite3VdbeAddOp2(v, OP_FifoRead, regOldRowid, 0);
}
if( triggers_exist ){
int regRowid;
int regRow;
int regCols;
/* Make cursor iCur point to the record that is being updated.
*/
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
/* Generate the OLD table
*/
regRowid = sqlite3GetTempReg(pParse);
regRow = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
if( !old_col_mask ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regRow);
sqlite-amalgamation.c view on Meta::CPAN
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
}
if( !isView && !IsVirtual(pTab) ){
/* Loop over every record that needs updating. We have to load
** the old data for each record to be updated because some columns
** might not change and we will need to copy the old value.
** Also, the old data is needed to delete the old index entries.
** So make the cursor point at the old record.
*/
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
/* If the record number will change, push the record number as it
** will be after the update. (The old record number is currently
** on top of the stack.)
*/
if( chngRowid ){
sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
sqlite-amalgamation.c view on Meta::CPAN
sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid,
aRegIdx, chngRowid, 1, -1, 0);
}
/* Increment the row counter
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
/* If there are triggers, close all the cursors after each iteration
** through the loop. The fire the after triggers.
*/
if( triggers_exist ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
*/
sqlite-amalgamation.c view on Meta::CPAN
** The following identity holds:
**
** WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm
**
** When a term is of the form:
**
** X <op> <expr>
**
** where X is a column name and <op> is one of certain operators,
** then WhereTerm.leftCursor and WhereTerm.leftColumn record the
** cursor number and column number for X. WhereTerm.operator records
** the <op> using a bitmask encoding defined by WO_xxx below. The
** use of a bitmask encoding for the operator allows us to search
** quickly for terms that match any of several different operators.
**
** prereqRight and prereqAll record sets of cursor numbers,
** but they do so indirectly. A single ExprMaskSet structure translates
** cursor number into bits and the translated bit is stored in the prereq
** fields. The translation is used in order to maximize the number of
** bits that will fit in a Bitmask. The VDBE cursor numbers might be
** spread out over the non-negative integers. For example, the cursor
** numbers might be 3, 8, 9, 10, 20, 23, 41, and 45. The ExprMaskSet
** translates these sparse cursor numbers into consecutive integers
** beginning with 0 in order to make the best possible use of the available
** bits in the Bitmask. So, in the example above, the cursor numbers
** would be mapped into integers 0 through 7.
*/
typedef struct WhereTerm WhereTerm;
struct WhereTerm {
Expr *pExpr; /* Pointer to the subexpression */
i16 iParent; /* Disable pWC->a[iParent] when this term disabled */
i16 leftCursor; /* Cursor number of X in "X <op> <expr>" */
i16 leftColumn; /* Column number of X in "X <op> <expr>" */
u16 eOperator; /* A WO_xx value describing <op> */
u8 flags; /* Bit flags. See below */
sqlite-amalgamation.c view on Meta::CPAN
Parse *pParse; /* The parser context */
ExprMaskSet *pMaskSet; /* Mapping of table indices to bitmasks */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
WhereTerm aStatic[10]; /* Initial static space for a[] */
};
/*
** An instance of the following structure keeps track of a mapping
** between VDBE cursor numbers and bits of the bitmasks in WhereTerm.
**
** The VDBE cursor numbers are small integers contained in
** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE
** clause, the cursor numbers might not begin with 0 and they might
** contain gaps in the numbering sequence. But we want to make maximum
** use of the bits in our bitmasks. This structure provides a mapping
** from the sparse cursor numbers into consecutive integers beginning
** with 0.
**
** If ExprMaskSet.ix[A]==B it means that The A-th bit of a Bitmask
** corresponds VDBE cursor number B. The A-th bit of a bitmask is 1<<A.
**
** For example, if the WHERE clause expression used these VDBE
** cursors: 4, 5, 8, 29, 57, 73. Then the ExprMaskSet structure
** would map those cursor numbers into bits 0 through 5.
**
** Note that the mapping is not necessarily ordered. In the example
** above, the mapping might go like this: 4->3, 5->1, 8->2, 29->0,
** 57->5, 73->4. Or one of 719 other combinations might be used. It
** does not really matter. What is important is that sparse cursor
** numbers all get mapped into bit numbers that begin with 0 and contain
** no gaps.
*/
struct ExprMaskSet {
int n; /* Number of assigned cursor values */
int ix[sizeof(Bitmask)*8]; /* Cursor assigned to each bit */
};
/*
** Bitmasks for the operators that indices are able to exploit. An
** OR-ed combination of these values can be used when searching for
** terms in the where clause.
*/
#define WO_IN 1
sqlite-amalgamation.c view on Meta::CPAN
whereSplit(pWC, pExpr->pRight, op);
}
}
/*
** Initialize an expression mask set
*/
#define initMaskSet(P) memset(P, 0, sizeof(*P))
/*
** Return the bitmask for the given cursor number. Return 0 if
** iCursor is not in the set.
*/
static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
int i;
for(i=0; i<pMaskSet->n; i++){
if( pMaskSet->ix[i]==iCursor ){
return ((Bitmask)1)<<i;
}
}
return 0;
}
/*
** Create a new mask for cursor iCursor.
**
** There is one cursor per table in the FROM clause. The number of
** tables in the FROM clause is limited by a test early in the
** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[]
** array will never overflow.
*/
static void createMask(ExprMaskSet *pMaskSet, int iCursor){
assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
pMaskSet->ix[pMaskSet->n++] = iCursor;
}
/*
** This routine walks (recursively) an expression tree and generates
** a bitmask indicating which tables are used in that expression
** tree.
**
** In order for this routine to work, the calling function must have
** previously invoked sqlite3ExprResolveNames() on the expression. See
** the header comment on that routine for additional information.
** The sqlite3ExprResolveNames() routines looks for column names and
** sets their opcodes to TK_COLUMN and their Expr.iTable fields to
** the VDBE cursor number of the table. This routine just has to
** translate the cursor numbers into bitmask values and OR all
** the bitmasks together.
*/
static Bitmask exprListTableUsage(ExprMaskSet*, ExprList*);
static Bitmask exprSelectTableUsage(ExprMaskSet*, Select*);
static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
Bitmask mask = 0;
if( p==0 ) return 0;
if( p->op==TK_COLUMN ){
mask = getMask(pMaskSet, p->iTable);
return mask;
sqlite-amalgamation.c view on Meta::CPAN
}
/*
** This routine decides if pIdx can be used to satisfy the ORDER BY
** clause. If it can, it returns 1. If pIdx cannot satisfy the
** ORDER BY clause, this routine returns 0.
**
** pOrderBy is an ORDER BY clause from a SELECT statement. pTab is the
** left-most table in the FROM clause of that same SELECT statement and
** the table has a cursor number of "base". pIdx is an index on pTab.
**
** nEqCol is the number of columns of pIdx that are used as equality
** constraints. Any of these columns may be missing from the ORDER BY
** clause and the match can still be a success.
**
** All terms of the ORDER BY that match against the index must be either
** ASC or DESC. (Terms of the ORDER BY clause past the end of a UNIQUE
** index do not need to satisfy this constraint.) The *pbRev value is
** set to 1 if the ORDER BY clause is all DESC and it is set to 0 if
** the ORDER BY clause is all ASC.
sqlite-amalgamation.c view on Meta::CPAN
** and initialized on the first invocation and reused on all subsequent
** invocations. The sqlite3_index_info structure is also used when
** code is generated to access the virtual table. The whereInfoDelete()
** routine takes care of freeing the sqlite3_index_info structure after
** everybody has finished with it.
*/
static double bestVirtualIndex(
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
Bitmask notReady, /* Mask of cursors that are not available */
ExprList *pOrderBy, /* The order by clause */
int orderByUsable, /* True if we can potential sort */
sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
){
Table *pTab = pSrc->pTab;
sqlite3_vtab *pVtab = pTab->pVtab;
sqlite3_index_info *pIdxInfo;
struct sqlite3_index_constraint *pIdxCons;
struct sqlite3_index_orderby *pIdxOrderBy;
struct sqlite3_index_constraint_usage *pUsage;
sqlite-amalgamation.c view on Meta::CPAN
** * Whether or not sorting must occur.
**
** * Whether or not there must be separate lookups in the
** index and in the main table.
**
*/
static double bestIndex(
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
Bitmask notReady, /* Mask of cursors that are not available */
ExprList *pOrderBy, /* The order by clause */
Index **ppIndex, /* Make *ppIndex point to the best index */
int *pFlags, /* Put flags describing this choice in *pFlags */
int *pnEq /* Put the number of == or IN constraints here */
){
WhereTerm *pTerm;
Index *bestIdx = 0; /* Index that gives the lowest cost */
double lowestCost; /* The cost of using bestIdx */
int bestFlags = 0; /* Flags associated with bestIdx */
int bestNEq = 0; /* Best value for nEq */
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
Index *pProbe; /* An index we are evaluating */
int rev; /* True to scan in reverse order */
int flags; /* Flags associated with pProbe */
int nEq; /* Number of == or IN constraints */
int eqTermMask; /* Mask of valid equality operators */
double cost; /* Cost of using pProbe */
WHERETRACE(("bestIndex: tbl=%s notReady=%llx\n", pSrc->pTab->zName, notReady));
lowestCost = SQLITE_BIG_DBL;
pProbe = pSrc->pTab->pIndex;
sqlite-amalgamation.c view on Meta::CPAN
static int codeAllEqualityTerms(
Parse *pParse, /* Parsing context */
WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
WhereClause *pWC, /* The WHERE clause */
Bitmask notReady, /* Which parts of FROM have not yet been coded */
int nExtraReg /* Number of extra registers to allocate */
){
int nEq = pLevel->nEq; /* The number of == or IN constraints to code */
Vdbe *v = pParse->pVdbe; /* The virtual machine under construction */
Index *pIdx = pLevel->pIdx; /* The index being used for this loop */
int iCur = pLevel->iTabCur; /* The cursor of the table */
WhereTerm *pTerm; /* A single constraint term */
int j; /* Loop counter */
int regBase; /* Base register */
/* Figure out how many memory cells we will need then allocate them.
** We always need at least one used to store the loop terminator
** value. If there are IN operators we'll need one for each == or
** IN constraint.
*/
pLevel->iMem = pParse->nMem + 1;
sqlite-amalgamation.c view on Meta::CPAN
** end \ Code generated
** end |-- by sqlite3WhereEnd()
** end /
**
** Note that the loops might not be nested in the order in which they
** appear in the FROM clause if a different order is better able to make
** use of indices. Note also that when the IN operator appears in
** the WHERE clause, it might result in additional nested loops for
** scanning through all values on the right-hand side of the IN.
**
** There are Btree cursors associated with each table. t1 uses cursor
** number pTabList->a[0].iCursor. t2 uses the cursor pTabList->a[1].iCursor.
** And so forth. This routine generates code to open those VDBE cursors
** and sqlite3WhereEnd() generates the code to close them.
**
** The code that sqlite3WhereBegin() generates leaves the cursors named
** in pTabList pointing at their appropriate entries. The [...] code
** can use OP_Column and OP_Rowid opcodes on these cursors to extract
** data from the various tables of the loop.
**
** If the WHERE clause is empty, the foreach loops must each scan their
** entire tables. Thus a three-way join is an O(N^3) operation. But if
** the tables have indices and there are terms in the WHERE clause that
** refer to those indices, a complete table scan can be avoided and the
** code will run much faster. Most of the work of this routine is checking
** to see if there are indices that can be used to speed up the loop.
**
** Terms of the WHERE clause are also used to limit which rows actually
sqlite-amalgamation.c view on Meta::CPAN
** An outer join of tables t1 and t2 is conceptally coded as follows:
**
** foreach row1 in t1 do
** flag = 0
** foreach row2 in t2 do
** start:
** ...
** flag = 1
** end
** if flag==0 then
** move the row2 cursor to a null row
** goto start
** fi
** end
**
** ORDER BY CLAUSE PROCESSING
**
** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
** if there is one. If there is no ORDER BY clause or if this routine
** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL.
**
sqlite-amalgamation.c view on Meta::CPAN
/* Special case: a WHERE clause that is constant. Evaluate the
** expression and either jump over all of the code or fall thru.
*/
if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pWhere = 0;
}
/* Assign a bit from the bitmask to every term in the FROM clause.
**
** When assigning bitmask values to FROM clause cursors, it must be
** the case that if X is the bitmask for the N-th FROM clause term then
** the bitmask for all FROM clause terms to the left of the N-th term
** is (X-1). An expression from the ON clause of a LEFT JOIN can use
** its Expr.iRightJoinTable value to find the bitmask of the right table
** of the join. Subtracting one from the right table bitmask gives a
** bitmask for all tables to the left of the join. Knowing the bitmask
** for all tables to the left of a left join is important. Ticket #3015.
*/
for(i=0; i<pTabList->nSrc; i++){
createMask(&maskSet, pTabList->a[i].iCursor);
sqlite-amalgamation.c view on Meta::CPAN
}
/* Chose the best index to use for each table in the FROM clause.
**
** This loop fills in the following fields:
**
** pWInfo->a[].pIdx The index to use for this level of the loop.
** pWInfo->a[].flags WHERE_xxx flags associated with pIdx
** pWInfo->a[].nEq The number of == and IN constraints
** pWInfo->a[].iFrom When term of the FROM clause is being coded
** pWInfo->a[].iTabCur The VDBE cursor for the database table
** pWInfo->a[].iIdxCur The VDBE cursor for the index
**
** This loop also figures out the nesting order of tables in the FROM
** clause.
*/
notReady = ~(Bitmask)0;
pTabItem = pTabList->a;
pLevel = pWInfo->a;
andFlags = ~0;
WHERETRACE(("*** Optimizer Start ***\n"));
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
sqlite-amalgamation.c view on Meta::CPAN
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
/* Generate the code to do the search. Each iteration of the for
** loop below generates code for a single nested loop of the VM
** program.
*/
notReady = ~(Bitmask)0;
for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
int j;
int iCur = pTabItem->iCursor; /* The VDBE cursor for the table */
Index *pIdx; /* The index we will be using */
int nxt; /* Where to jump to continue with the next IN case */
int iIdxCur; /* The VDBE cursor for the index */
int omitTable; /* True if we use the index only */
int bRev; /* True if we need to scan in reverse order */
pTabItem = &pTabList->a[pLevel->iFrom];
iCur = pTabItem->iCursor;
pIdx = pLevel->pIdx;
iIdxCur = pLevel->iIdxCur;
bRev = (pLevel->flags & WHERE_REVERSE)!=0;
omitTable = (pLevel->flags & WHERE_IDX_ONLY)!=0;
sqlite-amalgamation.c view on Meta::CPAN
}
testcase( pRangeStart && pRangeStart->eOperator & WO_LE );
testcase( pRangeStart && pRangeStart->eOperator & WO_GE );
testcase( pRangeEnd && pRangeEnd->eOperator & WO_LE );
testcase( pRangeEnd && pRangeEnd->eOperator & WO_GE );
startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE);
endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE);
start_constraints = pRangeStart || nEq>0;
/* Seek the index cursor to the start of the range. */
nConstraint = nEq;
if( pRangeStart ){
int dcc = pParse->disableColCache;
if( pRangeEnd ){
pParse->disableColCache++;
}
sqlite3ExprCode(pParse, pRangeStart->pExpr->pRight, regBase+nEq);
pParse->disableColCache = dcc;
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
nConstraint++;
sqlite-amalgamation.c view on Meta::CPAN
if( pRangeEnd ){
sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq);
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
codeApplyAffinity(pParse, regBase, nEq+1, pIdx);
nConstraint++;
}
/* Top of the loop body */
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
/* Check if the index cursor is past the end of the range. */
op = aEndOp[(pRangeEnd || nEq) * (1 + bRev)];
testcase( op==OP_Noop );
testcase( op==OP_IdxGE );
testcase( op==OP_IdxLT );
sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase,
SQLITE_INT_TO_PTR(nConstraint), P4_INT32);
sqlite3VdbeChangeP5(v, endEq!=bRev);
/* If there are inequality constraints, check that the value
** of the table column that the inequality contrains is not NULL.
** If it is, jump to the next iteration of the loop.
*/
r1 = sqlite3GetTempReg(pParse);
testcase( pLevel->flags & WHERE_BTM_LIMIT );
testcase( pLevel->flags & WHERE_TOP_LIMIT );
if( pLevel->flags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT) ){
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont);
}
/* Seek the table cursor, if required */
if( !omitTable ){
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */
}
sqlite3ReleaseTempReg(pParse, r1);
/* Record the instruction used to terminate the loop. Disable
** WHERE clause terms made redundant by the index range scan.
*/
pLevel->op = bRev ? OP_Prev : OP_Next;
sqlite-amalgamation.c view on Meta::CPAN
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->top);
sqlite3VdbeJumpHere(v, addr);
}
}
/* The "break" point is here, just past the end of the outer loop.
** Set it.
*/
sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
/* Close all of the cursors that were opened by sqlite3WhereBegin.
*/
for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab;
assert( pTab!=0 );
if( pTab->isEphem || pTab->pSelect ) continue;
if( !pWInfo->okOnePass && (pLevel->flags & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
if( pLevel->pIdx!=0 ){
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
}
/* If this scan uses an index, make code substitutions to read data
** from the index in preference to the table. Sometimes, this means
** the table need never be read from. This is a performance boost,
** as the vdbe level waits until the table is read before actually
** seeking the table cursor to the record corresponding to the current
** position in the index.
**
** Calls to the code generator in between sqlite3WhereBegin and
** sqlite3WhereEnd will have created code that references the table
** directly. This loop scans all that code looking for opcodes
** that reference the table and converts them into opcodes that
** reference the index.
*/
if( pLevel->pIdx ){
int k, j, last;
sqlite-amalgamation.c view on Meta::CPAN
** Defines the interface to tokenizers used by fulltext-search. There
** are three basic components:
**
** sqlite3_tokenizer_module is a singleton defining the tokenizer
** interface functions. This is essentially the class structure for
** tokenizers.
**
** sqlite3_tokenizer is used to define a particular tokenizer, perhaps
** including customization information defined at creation time.
**
** sqlite3_tokenizer_cursor is generated by a tokenizer to generate
** tokens from a particular input.
*/
#ifndef _FTS3_TOKENIZER_H_
#define _FTS3_TOKENIZER_H_
/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time.
** If tokenizers are to be allowed to call sqlite3_*() functions, then
** we will need a way to register the API consistently.
*/
sqlite-amalgamation.c view on Meta::CPAN
** functions that make up an implementation.
**
** When an fts3 table is created, it passes any arguments passed to
** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the
** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer
** implementation. The xCreate() function in turn returns an
** sqlite3_tokenizer structure representing the specific tokenizer to
** be used for the fts3 table (customized by the tokenizer clause arguments).
**
** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen()
** method is called. It returns an sqlite3_tokenizer_cursor object
** that may be used to tokenize a specific input buffer based on
** the tokenization rules supplied by a specific sqlite3_tokenizer
** object.
*/
typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
typedef struct sqlite3_tokenizer sqlite3_tokenizer;
typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
struct sqlite3_tokenizer_module {
/*
** Structure version. Should always be set to 0.
*/
int iVersion;
/*
** Create a new tokenizer. The values in the argv[] array are the
sqlite-amalgamation.c view on Meta::CPAN
sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */
);
/*
** Destroy an existing tokenizer. The fts3 module calls this method
** exactly once for each successful call to xCreate().
*/
int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
/*
** Create a tokenizer cursor to tokenize an input buffer. The caller
** is responsible for ensuring that the input buffer remains valid
** until the cursor is closed (using the xClose() method).
*/
int (*xOpen)(
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
const char *pInput, int nBytes, /* Input buffer */
sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */
);
/*
** Destroy an existing tokenizer cursor. The fts3 module calls this
** method exactly once for each successful call to xOpen().
*/
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
/*
** Retrieve the next token from the tokenizer cursor pCursor. This
** method should either return SQLITE_OK and set the values of the
** "OUT" variables identified below, or SQLITE_DONE to indicate that
** the end of the buffer has been reached, or an SQLite error code.
**
** *ppToken should be set to point at a buffer containing the
** normalized version of the token (i.e. after any case-folding and/or
** stemming has been performed). *pnBytes should be set to the length
** of this buffer in bytes. The input text that generated the token is
** identified by the byte offsets returned in *piStartOffset and
** *piEndOffset.
**
** The buffer *ppToken is set to point at is managed by the tokenizer
** implementation. It is only required to be valid until the next call
** to xNext() or xClose().
*/
/* TODO(shess) current implementation requires pInput to be
** nul-terminated. This should either be fixed, or pInput/nBytes
** should be converted to zInput.
*/
int (*xNext)(
sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */
const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
int *piStartOffset, /* OUT: Byte offset of token in input buffer */
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
int *piPosition /* OUT: Number of tokens returned before this one */
);
};
struct sqlite3_tokenizer {
const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
/* Tokenizer implementations will typically add additional fields */
};
struct sqlite3_tokenizer_cursor {
sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */
/* Tokenizer implementations will typically add additional fields */
};
#endif /* _FTS3_TOKENIZER_H_ */
/************** End of fts3_tokenizer.h **************************************/
/************** Continuing where we left off in fts3.c ***********************/
#ifndef SQLITE_CORE
SQLITE_EXTENSION_INIT1
#endif
sqlite-amalgamation.c view on Meta::CPAN
SEGDIR_SELECT_SEGMENT_STMT,
SEGDIR_SELECT_ALL_STMT,
SEGDIR_DELETE_ALL_STMT,
SEGDIR_COUNT_STMT,
MAX_STMT /* Always at end! */
} fulltext_statement;
/* These must exactly match the enum above. */
/* TODO(shess): Is there some risk that a statement will be used in two
** cursors at once, e.g. if a query joins a virtual table to itself?
** If so perhaps we should move some of these to the cursor object.
*/
static const char *const fulltext_zStatement[MAX_STMT] = {
/* CONTENT_INSERT */ NULL, /* generated in contentInsertStatement() */
/* CONTENT_SELECT */ NULL, /* generated in contentSelectStatement() */
/* CONTENT_UPDATE */ NULL, /* generated in contentUpdateStatement() */
/* CONTENT_DELETE */ "delete from %_content where docid = ?",
/* CONTENT_EXISTS */ "select docid from %_content limit 1",
/* BLOCK_INSERT */
"insert into %_segments (blockid, block) values (null, ?)",
sqlite-amalgamation.c view on Meta::CPAN
** initialized). iPrevDocid is the last docid written, used to make
** certain we're inserting in sorted order.
*/
int nPendingData;
#define kPendingThreshold (1*1024*1024)
sqlite_int64 iPrevDocid;
fts3Hash pendingTerms;
};
/*
** When the core wants to do a query, it create a cursor using a
** call to xOpen. This structure is an instance of a cursor. It
** is destroyed by xClose.
*/
typedef struct fulltext_cursor {
sqlite3_vtab_cursor base; /* Base class used by SQLite core */
QueryType iCursorType; /* Copy of sqlite3_index_info.idxNum */
sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */
int eof; /* True if at End Of Results */
Query q; /* Parsed query string */
Snippet snippet; /* Cached snippet for the current row */
int iColumn; /* Column being searched */
DataBuffer result; /* Doclist results from fulltextQuery */
DLReader reader; /* Result reader if result not empty */
} fulltext_cursor;
static struct fulltext_vtab *cursor_vtab(fulltext_cursor *c){
return (fulltext_vtab *) c->base.pVtab;
}
static const sqlite3_module fts3Module; /* forward declaration */
/* Return a dynamically generated statement of the form
* insert into %_content (docid, ...) values (?, ...)
*/
static const char *contentInsertStatement(fulltext_vtab *v){
StringBuffer sb;
sqlite-amalgamation.c view on Meta::CPAN
"drop table if exists %_content;"
"drop table if exists %_segments;"
"drop table if exists %_segdir;"
);
if( rc!=SQLITE_OK ) return rc;
fulltext_vtab_destroy((fulltext_vtab *)pVTab);
return SQLITE_OK;
}
static int fulltextOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
fulltext_cursor *c;
c = (fulltext_cursor *) sqlite3_malloc(sizeof(fulltext_cursor));
if( c ){
memset(c, 0, sizeof(fulltext_cursor));
/* sqlite will initialize c->base */
*ppCursor = &c->base;
FTSTRACE(("FTS3 Open %p: %p\n", pVTab, c));
return SQLITE_OK;
}else{
return SQLITE_NOMEM;
}
}
sqlite-amalgamation.c view on Meta::CPAN
*/
static void snippetOffsetsOfColumn(
Query *pQuery,
Snippet *pSnippet,
int iColumn,
const char *zDoc,
int nDoc
){
const sqlite3_tokenizer_module *pTModule; /* The tokenizer module */
sqlite3_tokenizer *pTokenizer; /* The specific tokenizer */
sqlite3_tokenizer_cursor *pTCursor; /* Tokenizer cursor */
fulltext_vtab *pVtab; /* The full text index */
int nColumn; /* Number of columns in the index */
const QueryTerm *aTerm; /* Query string terms */
int nTerm; /* Number of query string terms */
int i, j; /* Loop counters */
int rc; /* Return code */
unsigned int match, prevMatch; /* Phrase search bitmasks */
const char *zToken; /* Next token from the tokenizer */
int nToken; /* Size of zToken */
int iBegin, iEnd, iPos; /* Offsets of beginning and end */
sqlite-amalgamation.c view on Meta::CPAN
}
}
iDir -= 2;
}
}
/*
** Compute all offsets for the current row of the query.
** If the offsets have already been computed, this routine is a no-op.
*/
static void snippetAllOffsets(fulltext_cursor *p){
int nColumn;
int iColumn, i;
int iFirst, iLast;
fulltext_vtab *pFts;
if( p->snippet.nMatch ) return;
if( p->q.nTerms==0 ) return;
pFts = p->q.pFts;
nColumn = pFts->nColumn;
iColumn = (p->iCursorType - QUERY_FULLTEXT);
sqlite-amalgamation.c view on Meta::CPAN
/*
** Allowed values for Snippet.aMatch[].snStatus
*/
#define SNIPPET_IGNORE 0 /* It is ok to omit this match from the snippet */
#define SNIPPET_DESIRED 1 /* We want to include this match in the snippet */
/*
** Generate the text of a snippet.
*/
static void snippetText(
fulltext_cursor *pCursor, /* The cursor we need the snippet for */
const char *zStartMark, /* Markup to appear before each match */
const char *zEndMark, /* Markup to appear after each match */
const char *zEllipsis /* Ellipsis mark */
){
int i, j;
struct snippetMatch *aMatch;
int nMatch;
int nDesired;
StringBuffer sb;
int tailCol;
sqlite-amalgamation.c view on Meta::CPAN
if( tailEllipsis ){
appendWhiteSpace(&sb);
append(&sb, zEllipsis);
}
pCursor->snippet.zSnippet = stringBufferData(&sb);
pCursor->snippet.nSnippet = stringBufferLength(&sb);
}
/*
** Close the cursor. For additional information see the documentation
** on the xClose method of the virtual table interface.
*/
static int fulltextClose(sqlite3_vtab_cursor *pCursor){
fulltext_cursor *c = (fulltext_cursor *) pCursor;
FTSTRACE(("FTS3 Close %p\n", c));
sqlite3_finalize(c->pStmt);
queryClear(&c->q);
snippetClear(&c->snippet);
if( c->result.nData!=0 ) dlrDestroy(&c->reader);
dataBufferDestroy(&c->result);
sqlite3_free(c);
return SQLITE_OK;
}
static int fulltextNext(sqlite3_vtab_cursor *pCursor){
fulltext_cursor *c = (fulltext_cursor *) pCursor;
int rc;
FTSTRACE(("FTS3 Next %p\n", pCursor));
snippetClear(&c->snippet);
if( c->iCursorType < QUERY_FULLTEXT ){
/* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */
rc = sqlite3_step(c->pStmt);
switch( rc ){
case SQLITE_ROW:
c->eof = 0;
sqlite-amalgamation.c view on Meta::CPAN
** OR and "-" syntax is ignored. If inPhrase is false, then every
** term found is marked with nPhrase=0 and OR and "-" syntax is significant.
*/
static int tokenizeSegment(
sqlite3_tokenizer *pTokenizer, /* The tokenizer to use */
const char *pSegment, int nSegment, /* Query expression being parsed */
int inPhrase, /* True if within "..." */
Query *pQuery /* Append results here */
){
const sqlite3_tokenizer_module *pModule = pTokenizer->pModule;
sqlite3_tokenizer_cursor *pCursor;
int firstIndex = pQuery->nTerms;
int iCol;
int nTerm = 1;
int rc = pModule->xOpen(pTokenizer, pSegment, nSegment, &pCursor);
if( rc!=SQLITE_OK ) return rc;
pCursor->pTokenizer = pTokenizer;
while( 1 ){
const char *pToken;
sqlite-amalgamation.c view on Meta::CPAN
** the %_content table.
**
** If idxNum==QUERY_DOCID then do a docid lookup for a single entry
** in the %_content table.
**
** If idxNum>=QUERY_FULLTEXT then use the full text index. The
** column on the left-hand side of the MATCH operator is column
** number idxNum-QUERY_FULLTEXT, 0 indexed. argv[0] is the right-hand
** side of the MATCH operator.
*/
/* TODO(shess) Upgrade the cursor initialization and destruction to
** account for fulltextFilter() being called multiple times on the
** same cursor. The current solution is very fragile. Apply fix to
** fts3 as appropriate.
*/
static int fulltextFilter(
sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
int idxNum, const char *idxStr, /* Which indexing scheme to use */
int argc, sqlite3_value **argv /* Arguments for the indexing scheme */
){
fulltext_cursor *c = (fulltext_cursor *) pCursor;
fulltext_vtab *v = cursor_vtab(c);
int rc;
FTSTRACE(("FTS3 Filter %p\n",pCursor));
/* If the cursor has a statement that was not prepared according to
** idxNum, clear it. I believe all calls to fulltextFilter with a
** given cursor will have the same idxNum , but in this case it's
** easy to be safe.
*/
if( c->pStmt && c->iCursorType!=idxNum ){
sqlite3_finalize(c->pStmt);
c->pStmt = NULL;
}
/* Get a fresh statement appropriate to idxNum. */
/* TODO(shess): Add a prepared-statement cache in the vt structure.
** The cache must handle multiple open cursors. Easier to cache the
** statement variants at the vt to reduce malloc/realloc/free here.
** Or we could have a StringBuffer variant which allowed stack
** construction for small values.
*/
if( !c->pStmt ){
StringBuffer sb;
initStringBuffer(&sb);
append(&sb, "SELECT docid, ");
appendList(&sb, v->nColumn, v->azContentColumn);
append(&sb, " FROM %_content");
sqlite-amalgamation.c view on Meta::CPAN
if( rc!=SQLITE_OK ) return rc;
break;
default: /* full-text search */
{
const char *zQuery = (const char *)sqlite3_value_text(argv[0]);
assert( idxNum<=QUERY_FULLTEXT+v->nColumn);
assert( argc==1 );
queryClear(&c->q);
if( c->result.nData!=0 ){
/* This case happens if the same cursor is used repeatedly. */
dlrDestroy(&c->reader);
dataBufferReset(&c->result);
}else{
dataBufferInit(&c->result, 0);
}
rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->q);
if( rc!=SQLITE_OK ) return rc;
if( c->result.nData!=0 ){
dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData);
}
sqlite-amalgamation.c view on Meta::CPAN
}
}
return fulltextNext(pCursor);
}
/* This is the xEof method of the virtual table. The SQLite core
** calls this routine to find out if it has reached the end of
** a query's results set.
*/
static int fulltextEof(sqlite3_vtab_cursor *pCursor){
fulltext_cursor *c = (fulltext_cursor *) pCursor;
return c->eof;
}
/* This is the xColumn method of the virtual table. The SQLite
** core calls this method during a query when it needs the value
** of a column from the virtual table. This method needs to use
** one of the sqlite3_result_*() routines to store the requested
** value back in the pContext.
*/
static int fulltextColumn(sqlite3_vtab_cursor *pCursor,
sqlite3_context *pContext, int idxCol){
fulltext_cursor *c = (fulltext_cursor *) pCursor;
fulltext_vtab *v = cursor_vtab(c);
if( idxCol<v->nColumn ){
sqlite3_value *pVal = sqlite3_column_value(c->pStmt, idxCol+1);
sqlite3_result_value(pContext, pVal);
}else if( idxCol==v->nColumn ){
/* The extra column whose name is the same as the table.
** Return a blob which is a pointer to the cursor
*/
sqlite3_result_blob(pContext, &c, sizeof(c), SQLITE_TRANSIENT);
}else if( idxCol==v->nColumn+1 ){
/* The docid column, which is an alias for rowid. */
sqlite3_value *pVal = sqlite3_column_value(c->pStmt, 0);
sqlite3_result_value(pContext, pVal);
}
return SQLITE_OK;
}
/* This is the xRowid method. The SQLite core calls this routine to
** retrieve the rowid for the current row of the result set. fts3
** exposes %_content.docid as the rowid for the virtual table. The
** rowid should be written to *pRowid.
*/
static int fulltextRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
fulltext_cursor *c = (fulltext_cursor *) pCursor;
*pRowid = sqlite3_column_int64(c->pStmt, 0);
return SQLITE_OK;
}
/* Add all terms in [zText] to pendingTerms table. If [iColumn] > 0,
** we also store positions and offsets in the hash table using that
** column number.
*/
static int buildTerms(fulltext_vtab *v, sqlite_int64 iDocid,
const char *zText, int iColumn){
sqlite3_tokenizer *pTokenizer = v->pTokenizer;
sqlite3_tokenizer_cursor *pCursor;
const char *pToken;
int nTokenBytes;
int iStartOffset, iEndOffset, iPosition;
int rc;
rc = pTokenizer->pModule->xOpen(pTokenizer, zText, -1, &pCursor);
if( rc!=SQLITE_OK ) return rc;
pCursor->pTokenizer = pTokenizer;
while( SQLITE_OK==(rc=pTokenizer->pModule->xNext(pCursor,
sqlite-amalgamation.c view on Meta::CPAN
static void interiorReaderInit(const char *pData, int nData,
InteriorReader *pReader){
int n, nTerm;
/* Require at least the leading flag byte */
assert( nData>0 );
assert( pData[0]!='\0' );
CLEAR(pReader);
/* Decode the base blockid, and set the cursor to the first term. */
n = fts3GetVarint(pData+1, &pReader->iBlockid);
assert( 1+n<=nData );
pReader->pData = pData+1+n;
pReader->nData = nData-(1+n);
/* A single-child interior node (such as when a leaf node was too
** large for the segment directory) won't have any terms.
** Otherwise, decode the first term.
*/
if( pReader->nData==0 ){
sqlite-amalgamation.c view on Meta::CPAN
}
/*
** Implementation of the snippet() function for FTS3
*/
static void snippetFunc(
sqlite3_context *pContext,
int argc,
sqlite3_value **argv
){
fulltext_cursor *pCursor;
if( argc<1 ) return;
if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ||
sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){
sqlite3_result_error(pContext, "illegal first argument to html_snippet",-1);
}else{
const char *zStart = "<b>";
const char *zEnd = "</b>";
const char *zEllipsis = "<b>...</b>";
memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor));
if( argc>=2 ){
sqlite-amalgamation.c view on Meta::CPAN
}
/*
** Implementation of the offsets() function for FTS3
*/
static void snippetOffsetsFunc(
sqlite3_context *pContext,
int argc,
sqlite3_value **argv
){
fulltext_cursor *pCursor;
if( argc<1 ) return;
if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ||
sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){
sqlite3_result_error(pContext, "illegal first argument to offsets",-1);
}else{
memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor));
snippetAllOffsets(pCursor);
snippetOffsetText(&pCursor->snippet);
sqlite3_result_text(pContext,
pCursor->snippet.zOffset, pCursor->snippet.nOffset,
sqlite-amalgamation.c view on Meta::CPAN
dataBufferDestroy(&merged);
return rc;
}
/* Implement optimize() function for FTS3. optimize(t) merges all
** segments in the fts index into a single segment. 't' is the magic
** table-named column.
*/
static void optimizeFunc(sqlite3_context *pContext,
int argc, sqlite3_value **argv){
fulltext_cursor *pCursor;
if( argc>1 ){
sqlite3_result_error(pContext, "excess arguments to optimize()",-1);
}else if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ||
sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){
sqlite3_result_error(pContext, "illegal first argument to optimize",-1);
}else{
fulltext_vtab *v;
int i, rc, iMaxLevel;
OptLeavesReader *readers;
int nReaders;
LeafWriter writer;
sqlite3_stmt *s;
memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor));
v = cursor_vtab(pCursor);
/* Flush any buffered updates before optimizing. */
rc = flushPendingTerms(v);
if( rc!=SQLITE_OK ) goto err;
rc = segdir_count(v, &nReaders, &iMaxLevel);
if( rc!=SQLITE_OK ) goto err;
if( nReaders==0 || nReaders==1 ){
sqlite3_result_text(pContext, "Index already optimal", -1,
SQLITE_STATIC);
sqlite-amalgamation.c view on Meta::CPAN
** tests. TEXT result containing the ordered list of terms joined by
** spaces. dump_terms(t, level, idx) dumps the terms for the segment
** specified by level, idx (in %_segdir), while dump_terms(t) dumps
** all terms in the index. In both cases t is the fts table's magic
** table-named column.
*/
static void dumpTermsFunc(
sqlite3_context *pContext,
int argc, sqlite3_value **argv
){
fulltext_cursor *pCursor;
if( argc!=3 && argc!=1 ){
generateError(pContext, "dump_terms", "incorrect arguments");
}else if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ||
sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){
generateError(pContext, "dump_terms", "illegal first argument");
}else{
fulltext_vtab *v;
fts3Hash terms;
sqlite3_stmt *s = NULL;
int rc;
memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor));
v = cursor_vtab(pCursor);
/* If passed only the cursor column, get all segments. Otherwise
** get the segment described by the following two arguments.
*/
if( argc==1 ){
rc = sql_get_statement(v, SEGDIR_SELECT_ALL_STMT, &s);
}else{
rc = sql_get_statement(v, SEGDIR_SELECT_SEGMENT_STMT, &s);
if( rc==SQLITE_OK ){
rc = sqlite3_bind_int(s, 1, sqlite3_value_int(argv[1]));
if( rc==SQLITE_OK ){
rc = sqlite3_bind_int(s, 2, sqlite3_value_int(argv[2]));
sqlite-amalgamation.c view on Meta::CPAN
** In each case the number after the outer '[' is the docid. In the
** latter two cases, the number before the inner '[' is the column
** associated with the values within. For DL_POSITIONS the numbers
** within are the positions, for DL_POSITIONS_OFFSETS they are the
** position, the start offset, and the end offset.
*/
static void dumpDoclistFunc(
sqlite3_context *pContext,
int argc, sqlite3_value **argv
){
fulltext_cursor *pCursor;
if( argc!=2 && argc!=4 ){
generateError(pContext, "dump_doclist", "incorrect arguments");
}else if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ||
sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){
generateError(pContext, "dump_doclist", "illegal first argument");
}else if( sqlite3_value_text(argv[1])==NULL ||
sqlite3_value_text(argv[1])[0]=='\0' ){
generateError(pContext, "dump_doclist", "empty second argument");
}else{
const char *pTerm = (const char *)sqlite3_value_text(argv[1]);
const int nTerm = strlen(pTerm);
fulltext_vtab *v;
int rc;
DataBuffer doclist;
memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor));
v = cursor_vtab(pCursor);
dataBufferInit(&doclist, 0);
/* termSelect() yields the same logical doclist that queries are
** run against.
*/
if( argc==2 ){
rc = termSelect(v, v->nColumn, pTerm, nTerm, 0, DL_DEFAULT, &doclist);
}else{
sqlite3_stmt *s = NULL;
sqlite-amalgamation.c view on Meta::CPAN
/*
** Class derived from sqlite3_tokenizer
*/
typedef struct porter_tokenizer {
sqlite3_tokenizer base; /* Base class */
} porter_tokenizer;
/*
** Class derived from sqlit3_tokenizer_cursor
*/
typedef struct porter_tokenizer_cursor {
sqlite3_tokenizer_cursor base;
const char *zInput; /* input we are tokenizing */
int nInput; /* size of the input */
int iOffset; /* current position in zInput */
int iToken; /* index of next token to be returned */
char *zToken; /* storage for current token */
int nAllocated; /* space allocated to zToken buffer */
} porter_tokenizer_cursor;
/* Forward declaration */
static const sqlite3_tokenizer_module porterTokenizerModule;
/*
** Create a new tokenizer instance.
*/
static int porterCreate(
sqlite-amalgamation.c view on Meta::CPAN
/*
** Destroy a tokenizer
*/
static int porterDestroy(sqlite3_tokenizer *pTokenizer){
sqlite3_free(pTokenizer);
return SQLITE_OK;
}
/*
** Prepare to begin tokenizing a particular string. The input
** string to be tokenized is zInput[0..nInput-1]. A cursor
** used to incrementally tokenize this string is returned in
** *ppCursor.
*/
static int porterOpen(
sqlite3_tokenizer *pTokenizer, /* The tokenizer */
const char *zInput, int nInput, /* String to be tokenized */
sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */
){
porter_tokenizer_cursor *c;
c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));
if( c==NULL ) return SQLITE_NOMEM;
c->zInput = zInput;
if( zInput==0 ){
c->nInput = 0;
}else if( nInput<0 ){
c->nInput = (int)strlen(zInput);
}else{
c->nInput = nInput;
}
c->iOffset = 0; /* start tokenizing at the beginning */
c->iToken = 0;
c->zToken = NULL; /* no space allocated, yet. */
c->nAllocated = 0;
*ppCursor = &c->base;
return SQLITE_OK;
}
/*
** Close a tokenization cursor previously opened by a call to
** porterOpen() above.
*/
static int porterClose(sqlite3_tokenizer_cursor *pCursor){
porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor;
sqlite3_free(c->zToken);
sqlite3_free(c);
return SQLITE_OK;
}
/*
** Vowel or consonant
*/
static const char cType[] = {
0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,
1, 1, 1, 2, 1
sqlite-amalgamation.c view on Meta::CPAN
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
};
#define isDelim(C) (((ch=C)&0x80)==0 && (ch<0x30 || !porterIdChar[ch-0x30]))
/*
** Extract the next token from a tokenization cursor. The cursor must
** have been opened by a prior call to porterOpen().
*/
static int porterNext(
sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by porterOpen */
const char **pzToken, /* OUT: *pzToken is the token text */
int *pnBytes, /* OUT: Number of bytes in token */
int *piStartOffset, /* OUT: Starting offset of token */
int *piEndOffset, /* OUT: Ending offset of token */
int *piPosition /* OUT: Position integer of token */
){
porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor;
const char *z = c->zInput;
while( c->iOffset<c->nInput ){
int iStartOffset, ch;
/* Scan past delimiter characters */
while( c->iOffset<c->nInput && isDelim(z[c->iOffset]) ){
c->iOffset++;
}
sqlite-amalgamation.c view on Meta::CPAN
**
*/
static void testFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
fts3Hash *pHash;
sqlite3_tokenizer_module *p;
sqlite3_tokenizer *pTokenizer = 0;
sqlite3_tokenizer_cursor *pCsr = 0;
const char *zErr = 0;
const char *zName;
int nName;
const char *zInput;
int nInput;
const char *zArg = 0;
sqlite-amalgamation.c view on Meta::CPAN
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
typedef struct simple_tokenizer {
sqlite3_tokenizer base;
char delim[128]; /* flag ASCII delimiters */
} simple_tokenizer;
typedef struct simple_tokenizer_cursor {
sqlite3_tokenizer_cursor base;
const char *pInput; /* input we are tokenizing */
int nBytes; /* size of the input */
int iOffset; /* current position in pInput */
int iToken; /* index of next token to be returned */
char *pToken; /* storage for current token */
int nTokenAllocated; /* space allocated to zToken buffer */
} simple_tokenizer_cursor;
/* Forward declaration */
static const sqlite3_tokenizer_module simpleTokenizerModule;
static int simpleDelim(simple_tokenizer *t, unsigned char c){
return c<0x80 && t->delim[c];
}
/*
sqlite-amalgamation.c view on Meta::CPAN
/*
** Destroy a tokenizer
*/
static int simpleDestroy(sqlite3_tokenizer *pTokenizer){
sqlite3_free(pTokenizer);
return SQLITE_OK;
}
/*
** Prepare to begin tokenizing a particular string. The input
** string to be tokenized is pInput[0..nBytes-1]. A cursor
** used to incrementally tokenize this string is returned in
** *ppCursor.
*/
static int simpleOpen(
sqlite3_tokenizer *pTokenizer, /* The tokenizer */
const char *pInput, int nBytes, /* String to be tokenized */
sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */
){
simple_tokenizer_cursor *c;
c = (simple_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));
if( c==NULL ) return SQLITE_NOMEM;
c->pInput = pInput;
if( pInput==0 ){
c->nBytes = 0;
}else if( nBytes<0 ){
c->nBytes = (int)strlen(pInput);
}else{
c->nBytes = nBytes;
}
c->iOffset = 0; /* start tokenizing at the beginning */
c->iToken = 0;
c->pToken = NULL; /* no space allocated, yet. */
c->nTokenAllocated = 0;
*ppCursor = &c->base;
return SQLITE_OK;
}
/*
** Close a tokenization cursor previously opened by a call to
** simpleOpen() above.
*/
static int simpleClose(sqlite3_tokenizer_cursor *pCursor){
simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
sqlite3_free(c->pToken);
sqlite3_free(c);
return SQLITE_OK;
}
/*
** Extract the next token from a tokenization cursor. The cursor must
** have been opened by a prior call to simpleOpen().
*/
static int simpleNext(
sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */
const char **ppToken, /* OUT: *ppToken is the token text */
int *pnBytes, /* OUT: Number of bytes in token */
int *piStartOffset, /* OUT: Starting offset of token */
int *piEndOffset, /* OUT: Ending offset of token */
int *piPosition /* OUT: Position integer of token */
){
simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer;
unsigned char *p = (unsigned char *)c->pInput;
while( c->iOffset<c->nBytes ){
int iStartOffset;
int isAscii = 0;
/* Scan past delimiter characters */
while( c->iOffset<c->nBytes && simpleDelim(t, p[c->iOffset]) ){
c->iOffset++;
sqlite-amalgamation.c view on Meta::CPAN
** m = M/3
**
** If an R*-tree "Reinsert" operation is required, the same number of
** cells are removed from the overfull node and reinserted into the tree.
*/
#define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3)
#define RTREE_REINSERT(p) RTREE_MINCELLS(p)
#define RTREE_MAXCELLS 51
/*
** An rtree cursor object.
*/
struct RtreeCursor {
sqlite3_vtab_cursor base;
RtreeNode *pNode; /* Node cursor is currently pointing at */
int iCell; /* Index of current cell in pNode */
int iStrategy; /* Copy of idxNum search parameter */
int nConstraint; /* Number of entries in aConstraint */
RtreeConstraint *aConstraint; /* Search constraints. */
};
union RtreeCoord {
float f;
int i;
};
sqlite-amalgamation.c view on Meta::CPAN
if( rc==SQLITE_OK ){
rtreeRelease(pRtree);
}
return rc;
}
/*
** Rtree virtual table module xOpen method.
*/
static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
int rc = SQLITE_NOMEM;
RtreeCursor *pCsr;
pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor));
if( pCsr ){
memset(pCsr, 0, sizeof(RtreeCursor));
pCsr->base.pVtab = pVTab;
rc = SQLITE_OK;
}
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
return rc;
}
/*
** Rtree virtual table module xClose method.
*/
static int rtreeClose(sqlite3_vtab_cursor *cur){
Rtree *pRtree = (Rtree *)(cur->pVtab);
int rc;
RtreeCursor *pCsr = (RtreeCursor *)cur;
sqlite3_free(pCsr->aConstraint);
rc = nodeRelease(pRtree, pCsr->pNode);
sqlite3_free(pCsr);
return rc;
}
/*
** Rtree virtual table module xEof method.
**
** Return non-zero if the cursor does not currently point to a valid
** record (i.e if the scan has finished), or zero otherwise.
*/
static int rtreeEof(sqlite3_vtab_cursor *cur){
RtreeCursor *pCsr = (RtreeCursor *)cur;
return (pCsr->pNode==0);
}
/*
** Cursor pCursor currently points to a cell in a non-leaf page.
** Return true if the sub-tree headed by the cell is filtered
** (excluded) by the constraints in the pCursor->aConstraint[]
** array, or false otherwise.
*/
sqlite-amalgamation.c view on Meta::CPAN
case RTREE_EQ:
bRes = (p->rValue>cell_max || p->rValue<cell_min);
break;
}
}
return bRes;
}
/*
** Return true if the cell that cursor pCursor currently points to
** would be filtered (excluded) by the constraints in the
** pCursor->aConstraint[] array, or false otherwise.
**
** This function assumes that the cell is part of a leaf node.
*/
static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor){
RtreeCell cell;
int ii;
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
sqlite-amalgamation.c view on Meta::CPAN
RtreeNode *pParent = pNode->pParent;
if( pParent ){
return nodeRowidIndex(pRtree, pParent, pNode->iNode);
}
return -1;
}
/*
** Rtree virtual table module xNext method.
*/
static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
Rtree *pRtree = (Rtree *)(pVtabCursor->pVtab);
RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
int rc = SQLITE_OK;
if( pCsr->iStrategy==1 ){
/* This "scan" is a direct lookup by rowid. There is no next entry. */
nodeRelease(pRtree, pCsr->pNode);
pCsr->pNode = 0;
}
sqlite-amalgamation.c view on Meta::CPAN
iHeight++;
}
}
return rc;
}
/*
** Rtree virtual table module xRowid method.
*/
static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
assert(pCsr->pNode);
*pRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell);
return SQLITE_OK;
}
/*
** Rtree virtual table module xColumn method.
*/
static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
Rtree *pRtree = (Rtree *)cur->pVtab;
RtreeCursor *pCsr = (RtreeCursor *)cur;
if( i==0 ){
i64 iRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell);
sqlite3_result_int64(ctx, iRowid);
}else{
RtreeCoord c;
nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c);
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
sqlite-amalgamation.c view on Meta::CPAN
rc = sqlite3_reset(pRtree->pReadRowid);
}
return rc;
}
/*
** Rtree virtual table module xFilter method.
*/
static int rtreeFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
RtreeNode *pRoot = 0;
int ii;
int rc = SQLITE_OK;
sqlite-amalgamation.c view on Meta::CPAN
return rc;
}
static sqlite3_module rtreeModule = {
0, /* iVersion */
rtreeCreate, /* xCreate - create a table */
rtreeConnect, /* xConnect - connect to an existing table */
rtreeBestIndex, /* xBestIndex - Determine search strategy */
rtreeDisconnect, /* xDisconnect - Disconnect from a table */
rtreeDestroy, /* xDestroy - Drop a table */
rtreeOpen, /* xOpen - open a cursor */
rtreeClose, /* xClose - close a cursor */
rtreeFilter, /* xFilter - configure scan constraints */
rtreeNext, /* xNext - advance a cursor */
rtreeEof, /* xEof */
rtreeColumn, /* xColumn - read data */
rtreeRowid, /* xRowid - read data */
rtreeUpdate, /* xUpdate - write data */
0, /* xBegin - begin transaction */
0, /* xSync - sync transaction */
0, /* xCommit - commit transaction */
0, /* xRollback - rollback transaction */
0, /* xFindFunction - function overloading */
rtreeRename /* xRename - rename the table */
**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
*/
/*
** Structures used by the virtual table interface
*/
typedef struct sqlite3_vtab sqlite3_vtab;
typedef struct sqlite3_index_info sqlite3_index_info;
typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
typedef struct sqlite3_module sqlite3_module;
/*
** CAPI3REF: Virtual Table Object {H18000} <S20400>
** KEYWORDS: sqlite3_module
** EXPERIMENTAL
**
** A module is a class of virtual tables. Each module is defined
** by an instance of the following structure. This structure consists
** mostly of methods for the module.
int iVersion;
int (*xCreate)(sqlite3*, void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVTab, char**);
int (*xConnect)(sqlite3*, void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVTab, char**);
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
int (*xDisconnect)(sqlite3_vtab *pVTab);
int (*xDestroy)(sqlite3_vtab *pVTab);
int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
int (*xClose)(sqlite3_vtab_cursor*);
int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
int argc, sqlite3_value **argv);
int (*xNext)(sqlite3_vtab_cursor*);
int (*xEof)(sqlite3_vtab_cursor*);
int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);
int (*xBegin)(sqlite3_vtab *pVTab);
int (*xSync)(sqlite3_vtab *pVTab);
int (*xCommit)(sqlite3_vtab *pVTab);
int (*xRollback)(sqlite3_vtab *pVTab);
int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
};
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
int nRef; /* Used internally */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
/*
** CAPI3REF: Virtual Table Cursor Object {H18020} <S20400>
** KEYWORDS: sqlite3_vtab_cursor
** EXPERIMENTAL
**
** Every module implementation uses a subclass of the following structure
** to describe cursors that point into the virtual table and are used
** to loop through the virtual table. Cursors are created using the
** xOpen method of the module. Each module implementation will define
** the content of a cursor structure to suit its own needs.
**
** This superclass exists in order to define fields of the cursor that
** are common to all implementations.
**
** This interface is experimental and is subject to change or
** removal in future releases of SQLite.
*/
struct sqlite3_vtab_cursor {
sqlite3_vtab *pVtab; /* Virtual table of this cursor */
/* Virtual table implementations will typically add additional fields */
};
/*
** CAPI3REF: Declare The Schema Of A Virtual Table {H18280} <S20400>
** EXPERIMENTAL
**
** The xCreate and xConnect methods of a module use the following API
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
t/30insertfetch.t view on Meta::CPAN
# Insert a row into the test table.......
#
Test($state or $dbh->do("INSERT INTO $table"
. " VALUES(1, 'Alligator Descartes', 1111,"
. " 'Some Text')"), 'insert')
or DbiError($dbh->err, $dbh->errstr);
#
# Now, try SELECT'ing the row out.
#
Test($state or $cursor = $dbh->prepare("SELECT * FROM $table"
. " WHERE id = 1"),
'prepare select')
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute, 'execute select')
or DbiError($cursor->err, $cursor->errstr);
my ($row, $errstr);
Test($state or (defined($row = $cursor->fetchrow_arrayref) &&
!($cursor->errstr)), 'fetch select')
or DbiError($cursor->err, $cursor->errstr);
Test($state or ($row->[0] == 1 &&
$row->[1] eq 'Alligator Descartes' &&
$row->[2] == 1111 &&
$row->[3] eq 'Some Text'), 'compare select')
or DbiError($cursor->err, $cursor->errstr);
Test($state or $cursor->finish, 'finish select')
or DbiError($cursor->err, $cursor->errstr);
Test($state or undef $cursor || 1, 'undef select');
#
# ...and delete it........
#
Test($state or $dbh->do("DELETE FROM $table WHERE id = 1"), 'delete')
or DbiError($dbh->err, $dbh->errstr);
#
# Now, try SELECT'ing the row out. This should fail.
#
Test($state or $cursor = $dbh->prepare("SELECT * FROM $table"
. " WHERE id = 1"),
'prepare select deleted')
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute, 'execute select deleted')
or DbiError($cursor->err, $cursor->errstr);
Test($state or (!defined($row = $cursor->fetchrow_arrayref) &&
(!defined($errstr = $cursor->errstr) ||
$cursor->errstr eq '')), 'fetch select deleted')
or DbiError($cursor->err, $cursor->errstr);
Test($state or (!defined($row = $cursor->fetchrow_arrayref) &&
(!defined($errstr = $cursor->errstr) ||
$cursor->errstr eq '')), 'fetch on empty statement handler')
or DbiError($cursor->err, $cursor->errstr);
Test($state or $cursor->finish, 'finish select deleted')
or DbiError($cursor->err, $cursor->errstr);
Test($state or undef $cursor || 1, 'undef select deleted');
#
# Finally drop the test table.
#
Test($state or $dbh->do("DROP TABLE $table"), 'drop')
or DbiError($dbh->err, $dbh->errstr);
}
t/40bindparam.t view on Meta::CPAN
#
# Create a new table; EDIT THIS!
#
Test($state or ($def = TableDefinition($table,
["r_id", "INTEGER", 4, 0],
["name", "CHAR", 64, $COL_NULLABLE]) and
$dbh->do($def)), 'create', $def)
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor = $dbh->prepare("INSERT INTO $table"
. " VALUES (?, ?)"), 'prepare')
or DbiError($dbh->err, $dbh->errstr);
#
# Insert some rows
#
my $konig = "Andreas K\xf6nig";
# warn("Konig: $konig\n");
# Automatic type detection
my $numericVal = 1;
my $charVal = "Alligator Descartes";
Test($state or $cursor->execute($numericVal, $charVal), 'execute insert 1')
or DbiError($dbh->err, $dbh->errstr);
# Does the driver remember the automatically detected type?
Test($state or $cursor->execute("3", "Jochen Wiedmann"),
'execute insert num as string')
or DbiError($dbh->err, $dbh->errstr);
$numericVal = 2;
$charVal = "Tim Bunce";
Test($state or $cursor->execute($numericVal, $charVal), 'execute insert 2')
or DbiError($dbh->err, $dbh->errstr);
# Now try the explicit type settings
Test($state or $cursor->bind_param(1, " 4", SQL_INTEGER()), 'bind 1')
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->bind_param(2, $konig), 'bind 2')
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute, 'execute binds')
or DbiError($dbh->err, $dbh->errstr);
# Works undef -> NULL?
Test($state or $cursor->bind_param(1, 5, SQL_INTEGER()))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->bind_param(2, undef))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor -> finish, 'finish');
Test($state or undef $cursor || 1, 'undef cursor');
Test($state or $dbh -> disconnect, 'disconnect');
Test($state or undef $dbh || 1, 'undef dbh');
#
# And now retreive the rows using bind_columns
#
#
# Connect to the database
#
Test($state or $dbh = DBI->connect($test_dsn, $test_user, $test_password),
'connect for read')
or ServerError();
# $dbh->{NoUTF8Flag} = 1 if $] > 5.007;
Test($state or $cursor = $dbh->prepare("SELECT * FROM $table"
. " ORDER BY abs(r_id)"))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->bind_columns(undef, \$id, \$name))
or DbiError($dbh->err, $dbh->errstr);
Test($state or ($ref = $cursor->fetch) && $id == 1 &&
$name eq 'Alligator Descartes')
or printf("Alligator Query returned id = %s, name = %s, ref = %s, %d\n",
$id, $name, $ref, scalar(@$ref));
Test($state or (($ref = $cursor->fetch) && $id == 2 &&
$name eq 'Tim Bunce'))
or printf("Tim Query returned id = %s, name = %s, ref = %s, %d\n",
$id, $name, $ref, scalar(@$ref));
Test($state or (($ref = $cursor->fetch) && $id == 3 &&
$name eq 'Jochen Wiedmann'))
or printf("Jochen Query returned id = %s, name = %s, ref = %s, %d\n",
$id, $name, $ref, scalar(@$ref));
# warn("Konig: $konig\n");
Test($state or (($ref = $cursor->fetch) && $id == 4 &&
$name eq $konig))
or printf("Andreas Query returned id = %s, name = %s, ref = %s, %d\n",
$id, $name, $ref, scalar(@$ref));
# warn("$konig == $name ?\n");
Test($state or (($ref = $cursor->fetch) && $id == 5 &&
!defined($name)))
or printf("Query returned id = %s, name = %s, ref = %s, %d\n",
$id, $name, $ref, scalar(@$ref));
Test($state or undef $cursor or 1);
#
# Finally drop the test table.
#
Test($state or $dbh->do("DROP TABLE $table"))
or DbiError($dbh->err, $dbh->errstr);
}
t/40blobs.t view on Meta::CPAN
Test($state or ($sth = $dbh->prepare($query)))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $sth->bind_param(1, $blob, SQL_BLOB))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $sth->execute())
or DbiError($dbh->err, $dbh->errstr);
#
# Now, try SELECT'ing the row out.
#
Test($state or $cursor = $dbh->prepare("SELECT * FROM $table"
. " WHERE id = 1"))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($dbh->err, $dbh->errstr);
Test($state or (defined($row = $cursor->fetchrow_arrayref)))
or DbiError($cursor->err, $cursor->errstr);
Test($state or (@$row == 2 && $$row[0] == 1 && $$row[1] eq $blob))
or (ShowBlob($blob),
ShowBlob(defined($$row[1]) ? $$row[1] : ""));
Test($state or $cursor->finish)
or DbiError($cursor->err, $cursor->errstr);
Test($state or undef $cursor || 1)
or DbiError($cursor->err, $cursor->errstr);
#
# Finally drop the test table.
#
Test($state or $dbh->do("DROP TABLE $table"))
or DbiError($dbh->err, $dbh->errstr);
}
}
t/40listfields.t view on Meta::CPAN
or DbiError($dbh->err, $dbh->errstr);
#
# Create a new table
#
Test($state or ($def = TableDefinition($table, @table_def),
$dbh->do($def)))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor = $dbh->prepare("SELECT * FROM $table"))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($cursor->err, $cursor->errstr);
my $res;
Test($state or (($res = $cursor->{'NUM_OF_FIELDS'}) == @table_def))
or DbiError($cursor->err, $cursor->errstr);
if (!$state && $verbose) {
printf("Number of fields: %s\n", defined($res) ? $res : "undef");
}
Test($state or ($ref = $cursor->{'NAME'}) && @$ref == @table_def
&& (lc $$ref[0]) eq $table_def[0][0]
&& (lc $$ref[1]) eq $table_def[1][0])
or DbiError($cursor->err, $cursor->errstr);
if (!$state && $verbose) {
print "Names:\n";
for ($i = 0; $i < @$ref; $i++) {
print " ", $$ref[$i], "\n";
}
}
Test($state or ($dbdriver eq 'CSV') or ($dbdriver eq 'ConfFile')
or ($dbdriver eq 'SQLite')
or ($ref = $cursor->{'NULLABLE'}) && @$ref == @table_def
&& !($$ref[0] xor ($table_def[0][3] & $COL_NULLABLE))
&& !($$ref[1] xor ($table_def[1][3] & $COL_NULLABLE)))
or DbiError($cursor->err, $cursor->errstr);
if (!$state && $verbose) {
print "Nullable:\n";
for ($i = 0; $i < @$ref; $i++) {
print " ", ($$ref[$i] & $COL_NULLABLE) ? "yes" : "no", "\n";
}
}
Test($state or undef $cursor || 1);
#
# Drop the test table
#
Test($state or ($cursor = $dbh->prepare("DROP TABLE $table")))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($cursor->err, $cursor->errstr);
# NUM_OF_FIELDS should be zero (Non-Select)
Test($state or ($cursor->{'NUM_OF_FIELDS'} == 0))
or !$verbose or printf("NUM_OF_FIELDS is %s, not zero.\n",
$cursor->{'NUM_OF_FIELDS'});
Test($state or (undef $cursor) or 1);
}
t/40nulls.t view on Meta::CPAN
#
# Test whether or not a field containing a NULL is returned correctly
# as undef, or something much more bizarre
#
Test($state or $dbh->do("INSERT INTO $table VALUES"
. " ( NULL, 'NULL-valued id' )"))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor = $dbh->prepare("SELECT * FROM $table"
. " WHERE " . IsNull("id")))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($dbh->err, $dbh->errstr);
Test($state or ($rv = $cursor->fetchrow_arrayref) or $dbdriver eq 'CSV'
or $dbdriver eq 'ConfFile')
or DbiError($dbh->err, $dbh->errstr);
Test($state or (!defined($$rv[0]) and defined($$rv[1])) or
$dbdriver eq 'CSV' or $dbdriver eq 'ConfFile')
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->finish)
or DbiError($dbh->err, $dbh->errstr);
Test($state or undef $cursor || 1);
#
# Finally drop the test table.
#
Test($state or $dbh->do("DROP TABLE $table"))
or DbiError($dbh->err, $dbh->errstr);
}
t/40numrows.t view on Meta::CPAN
# This section should exercise the sth->rows
# method by preparing a statement, then finding the
# number of rows within it.
# Prior to execution, this should fail. After execution, the
# number of rows affected by the statement will be returned.
#
Test($state or $dbh->do("INSERT INTO $table"
. " VALUES( 1, 'Alligator Descartes' )"))
or DbiError($dbh->err, $dbh->errstr);
Test($state or ($cursor = $dbh->prepare("SELECT * FROM $table"
. " WHERE id = 1")))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($dbh->err, $dbh->errstr);
Test($state or ($numrows = TrueRows($cursor)) == 1)
or ErrMsgF("Expected to fetch 1 rows, got %s.\n", $numrows);
Test($state or $cursor->finish)
or DbiError($dbh->err, $dbh->errstr);
Test($state or undef $cursor or 1);
Test($state or $dbh->do("INSERT INTO $table"
. " VALUES( 2, 'Jochen Wiedmann' )"))
or DbiError($dbh->err, $dbh->errstr);
Test($state or ($cursor = $dbh->prepare("SELECT * FROM $table"
. " WHERE id >= 1")))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($dbh->err, $dbh->errstr);
Test($state or ($numrows = TrueRows($cursor)) == 2)
or ErrMsgF("Expected to fetch 2 rows, got %s.\n", $numrows);
Test($state or $cursor->finish)
or DbiError($dbh->err, $dbh->errstr);
Test($state or undef $cursor or 1);
Test($state or $dbh->do("INSERT INTO $table"
. " VALUES(3, 'Tim Bunce')"))
or DbiError($dbh->err, $dbh->errstr);
Test($state or ($cursor = $dbh->prepare("SELECT * FROM $table"
. " WHERE id >= 2")))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($dbh->err, $dbh->errstr);
Test($state or ($numrows = TrueRows($cursor)) == 2)
or ErrMsgF("Expected to fetch 2 rows, got %s.\n", $numrows);
Test($state or $cursor->finish)
or DbiError($dbh->err, $dbh->errstr);
Test($state or undef $cursor or 1);
#
# Finally drop the test table.
#
Test($state or $dbh->do("DROP TABLE $table"))
or DbiError($dbh->err, $dbh->errstr);
}