| Index: third_party/sqlite/amalgamation/sqlite3.04.c
|
| diff --git a/third_party/sqlite/amalgamation/sqlite3.04.c b/third_party/sqlite/amalgamation/sqlite3.04.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..df908ee56c008982ad7b72ccea0e97ac64aa9fea
|
| --- /dev/null
|
| +++ b/third_party/sqlite/amalgamation/sqlite3.04.c
|
| @@ -0,0 +1,24524 @@
|
| +/************** Begin file analyze.c *****************************************/
|
| +/*
|
| +** 2005-07-08
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains code associated with the ANALYZE command.
|
| +**
|
| +** The ANALYZE command gather statistics about the content of tables
|
| +** and indices. These statistics are made available to the query planner
|
| +** to help it make better decisions about how to perform queries.
|
| +**
|
| +** The following system tables are or have been supported:
|
| +**
|
| +** CREATE TABLE sqlite_stat1(tbl, idx, stat);
|
| +** CREATE TABLE sqlite_stat2(tbl, idx, sampleno, sample);
|
| +** CREATE TABLE sqlite_stat3(tbl, idx, nEq, nLt, nDLt, sample);
|
| +** CREATE TABLE sqlite_stat4(tbl, idx, nEq, nLt, nDLt, sample);
|
| +**
|
| +** Additional tables might be added in future releases of SQLite.
|
| +** The sqlite_stat2 table is not created or used unless the SQLite version
|
| +** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled
|
| +** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated.
|
| +** The sqlite_stat2 table is superseded by sqlite_stat3, which is only
|
| +** created and used by SQLite versions 3.7.9 and later and with
|
| +** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3
|
| +** is a superset of sqlite_stat2. The sqlite_stat4 is an enhanced
|
| +** version of sqlite_stat3 and is only available when compiled with
|
| +** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.1 and later. It is
|
| +** not possible to enable both STAT3 and STAT4 at the same time. If they
|
| +** are both enabled, then STAT4 takes precedence.
|
| +**
|
| +** For most applications, sqlite_stat1 provides all the statistics required
|
| +** for the query planner to make good choices.
|
| +**
|
| +** Format of sqlite_stat1:
|
| +**
|
| +** There is normally one row per index, with the index identified by the
|
| +** name in the idx column. The tbl column is the name of the table to
|
| +** which the index belongs. In each such row, the stat column will be
|
| +** a string consisting of a list of integers. The first integer in this
|
| +** list is the number of rows in the index. (This is the same as the
|
| +** number of rows in the table, except for partial indices.) The second
|
| +** integer is the average number of rows in the index that have the same
|
| +** value in the first column of the index. The third integer is the average
|
| +** number of rows in the index that have the same value for the first two
|
| +** columns. The N-th integer (for N>1) is the average number of rows in
|
| +** the index which have the same value for the first N-1 columns. For
|
| +** a K-column index, there will be K+1 integers in the stat column. If
|
| +** the index is unique, then the last integer will be 1.
|
| +**
|
| +** The list of integers in the stat column can optionally be followed
|
| +** by the keyword "unordered". The "unordered" keyword, if it is present,
|
| +** must be separated from the last integer by a single space. If the
|
| +** "unordered" keyword is present, then the query planner assumes that
|
| +** the index is unordered and will not use the index for a range query.
|
| +**
|
| +** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat
|
| +** column contains a single integer which is the (estimated) number of
|
| +** rows in the table identified by sqlite_stat1.tbl.
|
| +**
|
| +** Format of sqlite_stat2:
|
| +**
|
| +** The sqlite_stat2 is only created and is only used if SQLite is compiled
|
| +** with SQLITE_ENABLE_STAT2 and if the SQLite version number is between
|
| +** 3.6.18 and 3.7.8. The "stat2" table contains additional information
|
| +** about the distribution of keys within an index. The index is identified by
|
| +** the "idx" column and the "tbl" column is the name of the table to which
|
| +** the index belongs. There are usually 10 rows in the sqlite_stat2
|
| +** table for each index.
|
| +**
|
| +** The sqlite_stat2 entries for an index that have sampleno between 0 and 9
|
| +** inclusive are samples of the left-most key value in the index taken at
|
| +** evenly spaced points along the index. Let the number of samples be S
|
| +** (10 in the standard build) and let C be the number of rows in the index.
|
| +** Then the sampled rows are given by:
|
| +**
|
| +** rownumber = (i*C*2 + C)/(S*2)
|
| +**
|
| +** For i between 0 and S-1. Conceptually, the index space is divided into
|
| +** S uniform buckets and the samples are the middle row from each bucket.
|
| +**
|
| +** The format for sqlite_stat2 is recorded here for legacy reference. This
|
| +** version of SQLite does not support sqlite_stat2. It neither reads nor
|
| +** writes the sqlite_stat2 table. This version of SQLite only supports
|
| +** sqlite_stat3.
|
| +**
|
| +** Format for sqlite_stat3:
|
| +**
|
| +** The sqlite_stat3 format is a subset of sqlite_stat4. Hence, the
|
| +** sqlite_stat4 format will be described first. Further information
|
| +** about sqlite_stat3 follows the sqlite_stat4 description.
|
| +**
|
| +** Format for sqlite_stat4:
|
| +**
|
| +** As with sqlite_stat2, the sqlite_stat4 table contains histogram data
|
| +** to aid the query planner in choosing good indices based on the values
|
| +** that indexed columns are compared against in the WHERE clauses of
|
| +** queries.
|
| +**
|
| +** The sqlite_stat4 table contains multiple entries for each index.
|
| +** The idx column names the index and the tbl column is the table of the
|
| +** index. If the idx and tbl columns are the same, then the sample is
|
| +** of the INTEGER PRIMARY KEY. The sample column is a blob which is the
|
| +** binary encoding of a key from the index. The nEq column is a
|
| +** list of integers. The first integer is the approximate number
|
| +** of entries in the index whose left-most column exactly matches
|
| +** the left-most column of the sample. The second integer in nEq
|
| +** is the approximate number of entries in the index where the
|
| +** first two columns match the first two columns of the sample.
|
| +** And so forth. nLt is another list of integers that show the approximate
|
| +** number of entries that are strictly less than the sample. The first
|
| +** integer in nLt contains the number of entries in the index where the
|
| +** left-most column is less than the left-most column of the sample.
|
| +** The K-th integer in the nLt entry is the number of index entries
|
| +** where the first K columns are less than the first K columns of the
|
| +** sample. The nDLt column is like nLt except that it contains the
|
| +** number of distinct entries in the index that are less than the
|
| +** sample.
|
| +**
|
| +** There can be an arbitrary number of sqlite_stat4 entries per index.
|
| +** The ANALYZE command will typically generate sqlite_stat4 tables
|
| +** that contain between 10 and 40 samples which are distributed across
|
| +** the key space, though not uniformly, and which include samples with
|
| +** large nEq values.
|
| +**
|
| +** Format for sqlite_stat3 redux:
|
| +**
|
| +** The sqlite_stat3 table is like sqlite_stat4 except that it only
|
| +** looks at the left-most column of the index. The sqlite_stat3.sample
|
| +** column contains the actual value of the left-most column instead
|
| +** of a blob encoding of the complete index key as is found in
|
| +** sqlite_stat4.sample. The nEq, nLt, and nDLt entries of sqlite_stat3
|
| +** all contain just a single integer which is the same as the first
|
| +** integer in the equivalent columns in sqlite_stat4.
|
| +*/
|
| +#ifndef SQLITE_OMIT_ANALYZE
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +#if defined(SQLITE_ENABLE_STAT4)
|
| +# define IsStat4 1
|
| +# define IsStat3 0
|
| +#elif defined(SQLITE_ENABLE_STAT3)
|
| +# define IsStat4 0
|
| +# define IsStat3 1
|
| +#else
|
| +# define IsStat4 0
|
| +# define IsStat3 0
|
| +# undef SQLITE_STAT4_SAMPLES
|
| +# define SQLITE_STAT4_SAMPLES 1
|
| +#endif
|
| +#define IsStat34 (IsStat3+IsStat4) /* 1 for STAT3 or STAT4. 0 otherwise */
|
| +
|
| +/*
|
| +** This routine generates code that opens the sqlite_statN tables.
|
| +** The sqlite_stat1 table is always relevant. sqlite_stat2 is now
|
| +** obsolete. sqlite_stat3 and sqlite_stat4 are only opened when
|
| +** appropriate compile-time options are provided.
|
| +**
|
| +** If the sqlite_statN tables do not previously exist, it is created.
|
| +**
|
| +** Argument zWhere may be a pointer to a buffer containing a table name,
|
| +** or it may be a NULL pointer. If it is not NULL, then all entries in
|
| +** the sqlite_statN tables associated with the named table are deleted.
|
| +** If zWhere==0, then code is generated to delete all stat table entries.
|
| +*/
|
| +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 for this table or index */
|
| + const char *zWhereType /* Either "tbl" or "idx" */
|
| +){
|
| + static const struct {
|
| + const char *zName;
|
| + const char *zCols;
|
| + } aTable[] = {
|
| + { "sqlite_stat1", "tbl,idx,stat" },
|
| +#if defined(SQLITE_ENABLE_STAT4)
|
| + { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
|
| + { "sqlite_stat3", 0 },
|
| +#elif defined(SQLITE_ENABLE_STAT3)
|
| + { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" },
|
| + { "sqlite_stat4", 0 },
|
| +#else
|
| + { "sqlite_stat3", 0 },
|
| + { "sqlite_stat4", 0 },
|
| +#endif
|
| + };
|
| + int i;
|
| + sqlite3 *db = pParse->db;
|
| + Db *pDb;
|
| + Vdbe *v = sqlite3GetVdbe(pParse);
|
| + int aRoot[ArraySize(aTable)];
|
| + u8 aCreateTbl[ArraySize(aTable)];
|
| +
|
| + if( v==0 ) return;
|
| + assert( sqlite3BtreeHoldsAllMutexes(db) );
|
| + assert( sqlite3VdbeDb(v)==db );
|
| + pDb = &db->aDb[iDb];
|
| +
|
| + /* Create new statistic tables if they do not exist, or clear them
|
| + ** if they do already exist.
|
| + */
|
| + for(i=0; i<ArraySize(aTable); i++){
|
| + const char *zTab = aTable[i].zName;
|
| + Table *pStat;
|
| + if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){
|
| + if( aTable[i].zCols ){
|
| + /* The sqlite_statN table does not exist. Create it. Note that a
|
| + ** side-effect of the CREATE TABLE statement is to leave the rootpage
|
| + ** of the new table in register pParse->regRoot. This is important
|
| + ** because the OpenWrite opcode below will be needing it. */
|
| + sqlite3NestedParse(pParse,
|
| + "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols
|
| + );
|
| + aRoot[i] = pParse->regRoot;
|
| + aCreateTbl[i] = OPFLAG_P2ISREG;
|
| + }
|
| + }else{
|
| + /* The table already exists. If zWhere is not NULL, delete all entries
|
| + ** associated with the table zWhere. If zWhere is NULL, delete the
|
| + ** entire contents of the table. */
|
| + aRoot[i] = pStat->tnum;
|
| + aCreateTbl[i] = 0;
|
| + sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
|
| + if( zWhere ){
|
| + sqlite3NestedParse(pParse,
|
| + "DELETE FROM %Q.%s WHERE %s=%Q",
|
| + pDb->zName, zTab, zWhereType, zWhere
|
| + );
|
| + }else{
|
| + /* The sqlite_stat[134] table already exists. Delete all rows. */
|
| + sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Open the sqlite_stat[134] tables for writing. */
|
| + for(i=0; aTable[i].zCols; i++){
|
| + assert( i<ArraySize(aTable) );
|
| + sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
|
| + sqlite3VdbeChangeP5(v, aCreateTbl[i]);
|
| + VdbeComment((v, aTable[i].zName));
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Recommended number of samples for sqlite_stat4
|
| +*/
|
| +#ifndef SQLITE_STAT4_SAMPLES
|
| +# define SQLITE_STAT4_SAMPLES 24
|
| +#endif
|
| +
|
| +/*
|
| +** Three SQL functions - stat_init(), stat_push(), and stat_get() -
|
| +** share an instance of the following structure to hold their state
|
| +** information.
|
| +*/
|
| +typedef struct Stat4Accum Stat4Accum;
|
| +typedef struct Stat4Sample Stat4Sample;
|
| +struct Stat4Sample {
|
| + tRowcnt *anEq; /* sqlite_stat4.nEq */
|
| + tRowcnt *anDLt; /* sqlite_stat4.nDLt */
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + tRowcnt *anLt; /* sqlite_stat4.nLt */
|
| + union {
|
| + i64 iRowid; /* Rowid in main table of the key */
|
| + u8 *aRowid; /* Key for WITHOUT ROWID tables */
|
| + } u;
|
| + u32 nRowid; /* Sizeof aRowid[] */
|
| + u8 isPSample; /* True if a periodic sample */
|
| + int iCol; /* If !isPSample, the reason for inclusion */
|
| + u32 iHash; /* Tiebreaker hash */
|
| +#endif
|
| +};
|
| +struct Stat4Accum {
|
| + tRowcnt nRow; /* Number of rows in the entire table */
|
| + tRowcnt nPSample; /* How often to do a periodic sample */
|
| + int nCol; /* Number of columns in index + pk/rowid */
|
| + int nKeyCol; /* Number of index columns w/o the pk/rowid */
|
| + int mxSample; /* Maximum number of samples to accumulate */
|
| + Stat4Sample current; /* Current row as a Stat4Sample */
|
| + u32 iPrn; /* Pseudo-random number used for sampling */
|
| + Stat4Sample *aBest; /* Array of nCol best samples */
|
| + int iMin; /* Index in a[] of entry with minimum score */
|
| + int nSample; /* Current number of samples */
|
| + int iGet; /* Index of current sample accessed by stat_get() */
|
| + Stat4Sample *a; /* Array of mxSample Stat4Sample objects */
|
| + sqlite3 *db; /* Database connection, for malloc() */
|
| +};
|
| +
|
| +/* Reclaim memory used by a Stat4Sample
|
| +*/
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| +static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
| + assert( db!=0 );
|
| + if( p->nRowid ){
|
| + sqlite3DbFree(db, p->u.aRowid);
|
| + p->nRowid = 0;
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +/* Initialize the BLOB value of a ROWID
|
| +*/
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| +static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
| + assert( db!=0 );
|
| + if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
| + p->u.aRowid = sqlite3DbMallocRaw(db, n);
|
| + if( p->u.aRowid ){
|
| + p->nRowid = n;
|
| + memcpy(p->u.aRowid, pData, n);
|
| + }else{
|
| + p->nRowid = 0;
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +/* Initialize the INTEGER value of a ROWID.
|
| +*/
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| +static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
| + assert( db!=0 );
|
| + if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
| + p->nRowid = 0;
|
| + p->u.iRowid = iRowid;
|
| +}
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** Copy the contents of object (*pFrom) into (*pTo).
|
| +*/
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| +static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
| + pTo->isPSample = pFrom->isPSample;
|
| + pTo->iCol = pFrom->iCol;
|
| + pTo->iHash = pFrom->iHash;
|
| + memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol);
|
| + memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol);
|
| + memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol);
|
| + if( pFrom->nRowid ){
|
| + sampleSetRowid(p->db, pTo, pFrom->nRowid, pFrom->u.aRowid);
|
| + }else{
|
| + sampleSetRowidInt64(p->db, pTo, pFrom->u.iRowid);
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** Reclaim all memory of a Stat4Accum structure.
|
| +*/
|
| +static void stat4Destructor(void *pOld){
|
| + Stat4Accum *p = (Stat4Accum*)pOld;
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + int i;
|
| + for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
| + for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
|
| + sampleClear(p->db, &p->current);
|
| +#endif
|
| + sqlite3DbFree(p->db, p);
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the stat_init(N,K,C) SQL function. The three parameters
|
| +** are:
|
| +** N: The number of columns in the index including the rowid/pk (note 1)
|
| +** K: The number of columns in the index excluding the rowid/pk.
|
| +** C: The number of rows in the index (note 2)
|
| +**
|
| +** Note 1: In the special case of the covering index that implements a
|
| +** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
|
| +** total number of columns in the table.
|
| +**
|
| +** Note 2: C is only used for STAT3 and STAT4.
|
| +**
|
| +** For indexes on ordinary rowid tables, N==K+1. But for indexes on
|
| +** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
|
| +** PRIMARY KEY of the table. The covering index that implements the
|
| +** original WITHOUT ROWID table as N==K as a special case.
|
| +**
|
| +** This routine allocates the Stat4Accum object in heap memory. The return
|
| +** value is a pointer to the Stat4Accum object. The datatype of the
|
| +** return value is BLOB, but it is really just a pointer to the Stat4Accum
|
| +** object.
|
| +*/
|
| +static void statInit(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + Stat4Accum *p;
|
| + int nCol; /* Number of columns in index being sampled */
|
| + int nKeyCol; /* Number of key columns */
|
| + int nColUp; /* nCol rounded up for alignment */
|
| + int n; /* Bytes of space to allocate */
|
| + sqlite3 *db; /* Database connection */
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + int mxSample = SQLITE_STAT4_SAMPLES;
|
| +#endif
|
| +
|
| + /* Decode the three function arguments */
|
| + UNUSED_PARAMETER(argc);
|
| + nCol = sqlite3_value_int(argv[0]);
|
| + assert( nCol>0 );
|
| + nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol;
|
| + nKeyCol = sqlite3_value_int(argv[1]);
|
| + assert( nKeyCol<=nCol );
|
| + assert( nKeyCol>0 );
|
| +
|
| + /* Allocate the space required for the Stat4Accum object */
|
| + n = sizeof(*p)
|
| + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
|
| + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
|
| + + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
|
| + + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
|
| +#endif
|
| + ;
|
| + db = sqlite3_context_db_handle(context);
|
| + p = sqlite3DbMallocZero(db, n);
|
| + if( p==0 ){
|
| + sqlite3_result_error_nomem(context);
|
| + return;
|
| + }
|
| +
|
| + p->db = db;
|
| + p->nRow = 0;
|
| + p->nCol = nCol;
|
| + p->nKeyCol = nKeyCol;
|
| + p->current.anDLt = (tRowcnt*)&p[1];
|
| + p->current.anEq = &p->current.anDLt[nColUp];
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + {
|
| + u8 *pSpace; /* Allocated space not yet assigned */
|
| + int i; /* Used to iterate through p->aSample[] */
|
| +
|
| + p->iGet = -1;
|
| + p->mxSample = mxSample;
|
| + p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
|
| + p->current.anLt = &p->current.anEq[nColUp];
|
| + p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
|
| +
|
| + /* Set up the Stat4Accum.a[] and aBest[] arrays */
|
| + p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
|
| + p->aBest = &p->a[mxSample];
|
| + pSpace = (u8*)(&p->a[mxSample+nCol]);
|
| + for(i=0; i<(mxSample+nCol); i++){
|
| + p->a[i].anEq = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
|
| + p->a[i].anLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
|
| + p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
|
| + }
|
| + assert( (pSpace - (u8*)p)==n );
|
| +
|
| + for(i=0; i<nCol; i++){
|
| + p->aBest[i].iCol = i;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* Return a pointer to the allocated object to the caller. Note that
|
| + ** only the pointer (the 2nd parameter) matters. The size of the object
|
| + ** (given by the 3rd parameter) is never used and can be any positive
|
| + ** value. */
|
| + sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
|
| +}
|
| +static const FuncDef statInitFuncdef = {
|
| + 2+IsStat34, /* nArg */
|
| + SQLITE_UTF8, /* funcFlags */
|
| + 0, /* pUserData */
|
| + 0, /* pNext */
|
| + statInit, /* xFunc */
|
| + 0, /* xStep */
|
| + 0, /* xFinalize */
|
| + "stat_init", /* zName */
|
| + 0, /* pHash */
|
| + 0 /* pDestructor */
|
| +};
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT4
|
| +/*
|
| +** pNew and pOld are both candidate non-periodic samples selected for
|
| +** the same column (pNew->iCol==pOld->iCol). Ignoring this column and
|
| +** considering only any trailing columns and the sample hash value, this
|
| +** function returns true if sample pNew is to be preferred over pOld.
|
| +** In other words, if we assume that the cardinalities of the selected
|
| +** column for pNew and pOld are equal, is pNew to be preferred over pOld.
|
| +**
|
| +** This function assumes that for each argument sample, the contents of
|
| +** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
|
| +*/
|
| +static int sampleIsBetterPost(
|
| + Stat4Accum *pAccum,
|
| + Stat4Sample *pNew,
|
| + Stat4Sample *pOld
|
| +){
|
| + int nCol = pAccum->nCol;
|
| + int i;
|
| + assert( pNew->iCol==pOld->iCol );
|
| + for(i=pNew->iCol+1; i<nCol; i++){
|
| + if( pNew->anEq[i]>pOld->anEq[i] ) return 1;
|
| + if( pNew->anEq[i]<pOld->anEq[i] ) return 0;
|
| + }
|
| + if( pNew->iHash>pOld->iHash ) return 1;
|
| + return 0;
|
| +}
|
| +#endif
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| +/*
|
| +** Return true if pNew is to be preferred over pOld.
|
| +**
|
| +** This function assumes that for each argument sample, the contents of
|
| +** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
|
| +*/
|
| +static int sampleIsBetter(
|
| + Stat4Accum *pAccum,
|
| + Stat4Sample *pNew,
|
| + Stat4Sample *pOld
|
| +){
|
| + tRowcnt nEqNew = pNew->anEq[pNew->iCol];
|
| + tRowcnt nEqOld = pOld->anEq[pOld->iCol];
|
| +
|
| + assert( pOld->isPSample==0 && pNew->isPSample==0 );
|
| + assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) );
|
| +
|
| + if( (nEqNew>nEqOld) ) return 1;
|
| +#ifdef SQLITE_ENABLE_STAT4
|
| + if( nEqNew==nEqOld ){
|
| + if( pNew->iCol<pOld->iCol ) return 1;
|
| + return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld));
|
| + }
|
| + return 0;
|
| +#else
|
| + return (nEqNew==nEqOld && pNew->iHash>pOld->iHash);
|
| +#endif
|
| +}
|
| +
|
| +/*
|
| +** Copy the contents of sample *pNew into the p->a[] array. If necessary,
|
| +** remove the least desirable sample from p->a[] to make room.
|
| +*/
|
| +static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
| + Stat4Sample *pSample = 0;
|
| + int i;
|
| +
|
| + assert( IsStat4 || nEqZero==0 );
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT4
|
| + if( pNew->isPSample==0 ){
|
| + Stat4Sample *pUpgrade = 0;
|
| + assert( pNew->anEq[pNew->iCol]>0 );
|
| +
|
| + /* This sample is being added because the prefix that ends in column
|
| + ** iCol occurs many times in the table. However, if we have already
|
| + ** added a sample that shares this prefix, there is no need to add
|
| + ** this one. Instead, upgrade the priority of the highest priority
|
| + ** existing sample that shares this prefix. */
|
| + for(i=p->nSample-1; i>=0; i--){
|
| + Stat4Sample *pOld = &p->a[i];
|
| + if( pOld->anEq[pNew->iCol]==0 ){
|
| + if( pOld->isPSample ) return;
|
| + assert( pOld->iCol>pNew->iCol );
|
| + assert( sampleIsBetter(p, pNew, pOld) );
|
| + if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){
|
| + pUpgrade = pOld;
|
| + }
|
| + }
|
| + }
|
| + if( pUpgrade ){
|
| + pUpgrade->iCol = pNew->iCol;
|
| + pUpgrade->anEq[pUpgrade->iCol] = pNew->anEq[pUpgrade->iCol];
|
| + goto find_new_min;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* If necessary, remove sample iMin to make room for the new sample. */
|
| + if( p->nSample>=p->mxSample ){
|
| + Stat4Sample *pMin = &p->a[p->iMin];
|
| + tRowcnt *anEq = pMin->anEq;
|
| + tRowcnt *anLt = pMin->anLt;
|
| + tRowcnt *anDLt = pMin->anDLt;
|
| + sampleClear(p->db, pMin);
|
| + memmove(pMin, &pMin[1], sizeof(p->a[0])*(p->nSample-p->iMin-1));
|
| + pSample = &p->a[p->nSample-1];
|
| + pSample->nRowid = 0;
|
| + pSample->anEq = anEq;
|
| + pSample->anDLt = anDLt;
|
| + pSample->anLt = anLt;
|
| + p->nSample = p->mxSample-1;
|
| + }
|
| +
|
| + /* The "rows less-than" for the rowid column must be greater than that
|
| + ** for the last sample in the p->a[] array. Otherwise, the samples would
|
| + ** be out of order. */
|
| +#ifdef SQLITE_ENABLE_STAT4
|
| + assert( p->nSample==0
|
| + || pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] );
|
| +#endif
|
| +
|
| + /* Insert the new sample */
|
| + pSample = &p->a[p->nSample];
|
| + sampleCopy(p, pSample, pNew);
|
| + p->nSample++;
|
| +
|
| + /* Zero the first nEqZero entries in the anEq[] array. */
|
| + memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero);
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT4
|
| + find_new_min:
|
| +#endif
|
| + if( p->nSample>=p->mxSample ){
|
| + int iMin = -1;
|
| + for(i=0; i<p->mxSample; i++){
|
| + if( p->a[i].isPSample ) continue;
|
| + if( iMin<0 || sampleIsBetter(p, &p->a[iMin], &p->a[i]) ){
|
| + iMin = i;
|
| + }
|
| + }
|
| + assert( iMin>=0 );
|
| + p->iMin = iMin;
|
| + }
|
| +}
|
| +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
| +
|
| +/*
|
| +** Field iChng of the index being scanned has changed. So at this point
|
| +** p->current contains a sample that reflects the previous row of the
|
| +** index. The value of anEq[iChng] and subsequent anEq[] elements are
|
| +** correct at this point.
|
| +*/
|
| +static void samplePushPrevious(Stat4Accum *p, int iChng){
|
| +#ifdef SQLITE_ENABLE_STAT4
|
| + int i;
|
| +
|
| + /* Check if any samples from the aBest[] array should be pushed
|
| + ** into IndexSample.a[] at this point. */
|
| + for(i=(p->nCol-2); i>=iChng; i--){
|
| + Stat4Sample *pBest = &p->aBest[i];
|
| + pBest->anEq[i] = p->current.anEq[i];
|
| + if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
|
| + sampleInsert(p, pBest, i);
|
| + }
|
| + }
|
| +
|
| + /* Update the anEq[] fields of any samples already collected. */
|
| + for(i=p->nSample-1; i>=0; i--){
|
| + int j;
|
| + for(j=iChng; j<p->nCol; j++){
|
| + if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
|
| + }
|
| + }
|
| +#endif
|
| +
|
| +#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4)
|
| + if( iChng==0 ){
|
| + tRowcnt nLt = p->current.anLt[0];
|
| + tRowcnt nEq = p->current.anEq[0];
|
| +
|
| + /* Check if this is to be a periodic sample. If so, add it. */
|
| + if( (nLt/p->nPSample)!=(nLt+nEq)/p->nPSample ){
|
| + p->current.isPSample = 1;
|
| + sampleInsert(p, &p->current, 0);
|
| + p->current.isPSample = 0;
|
| + }else
|
| +
|
| + /* Or if it is a non-periodic sample. Add it in this case too. */
|
| + if( p->nSample<p->mxSample
|
| + || sampleIsBetter(p, &p->current, &p->a[p->iMin])
|
| + ){
|
| + sampleInsert(p, &p->current, 0);
|
| + }
|
| + }
|
| +#endif
|
| +
|
| +#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + UNUSED_PARAMETER( p );
|
| + UNUSED_PARAMETER( iChng );
|
| +#endif
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the stat_push SQL function: stat_push(P,C,R)
|
| +** Arguments:
|
| +**
|
| +** P Pointer to the Stat4Accum object created by stat_init()
|
| +** C Index of left-most column to differ from previous row
|
| +** R Rowid for the current row. Might be a key record for
|
| +** WITHOUT ROWID tables.
|
| +**
|
| +** This SQL function always returns NULL. It's purpose it to accumulate
|
| +** statistical data and/or samples in the Stat4Accum object about the
|
| +** index being analyzed. The stat_get() SQL function will later be used to
|
| +** extract relevant information for constructing the sqlite_statN tables.
|
| +**
|
| +** The R parameter is only used for STAT3 and STAT4
|
| +*/
|
| +static void statPush(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + int i;
|
| +
|
| + /* The three function arguments */
|
| + Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
| + int iChng = sqlite3_value_int(argv[1]);
|
| +
|
| + UNUSED_PARAMETER( argc );
|
| + UNUSED_PARAMETER( context );
|
| + assert( p->nCol>0 );
|
| + assert( iChng<p->nCol );
|
| +
|
| + if( p->nRow==0 ){
|
| + /* This is the first call to this function. Do initialization. */
|
| + for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
|
| + }else{
|
| + /* Second and subsequent calls get processed here */
|
| + samplePushPrevious(p, iChng);
|
| +
|
| + /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
| + ** to the current row of the index. */
|
| + for(i=0; i<iChng; i++){
|
| + p->current.anEq[i]++;
|
| + }
|
| + for(i=iChng; i<p->nCol; i++){
|
| + p->current.anDLt[i]++;
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + p->current.anLt[i] += p->current.anEq[i];
|
| +#endif
|
| + p->current.anEq[i] = 1;
|
| + }
|
| + }
|
| + p->nRow++;
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
|
| + sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
|
| + }else{
|
| + sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
|
| + sqlite3_value_blob(argv[2]));
|
| + }
|
| + p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
|
| +#endif
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT4
|
| + {
|
| + tRowcnt nLt = p->current.anLt[p->nCol-1];
|
| +
|
| + /* Check if this is to be a periodic sample. If so, add it. */
|
| + if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){
|
| + p->current.isPSample = 1;
|
| + p->current.iCol = 0;
|
| + sampleInsert(p, &p->current, p->nCol-1);
|
| + p->current.isPSample = 0;
|
| + }
|
| +
|
| + /* Update the aBest[] array. */
|
| + for(i=0; i<(p->nCol-1); i++){
|
| + p->current.iCol = i;
|
| + if( i>=iChng || sampleIsBetterPost(p, &p->current, &p->aBest[i]) ){
|
| + sampleCopy(p, &p->aBest[i], &p->current);
|
| + }
|
| + }
|
| + }
|
| +#endif
|
| +}
|
| +static const FuncDef statPushFuncdef = {
|
| + 2+IsStat34, /* nArg */
|
| + SQLITE_UTF8, /* funcFlags */
|
| + 0, /* pUserData */
|
| + 0, /* pNext */
|
| + statPush, /* xFunc */
|
| + 0, /* xStep */
|
| + 0, /* xFinalize */
|
| + "stat_push", /* zName */
|
| + 0, /* pHash */
|
| + 0 /* pDestructor */
|
| +};
|
| +
|
| +#define STAT_GET_STAT1 0 /* "stat" column of stat1 table */
|
| +#define STAT_GET_ROWID 1 /* "rowid" column of stat[34] entry */
|
| +#define STAT_GET_NEQ 2 /* "neq" column of stat[34] entry */
|
| +#define STAT_GET_NLT 3 /* "nlt" column of stat[34] entry */
|
| +#define STAT_GET_NDLT 4 /* "ndlt" column of stat[34] entry */
|
| +
|
| +/*
|
| +** Implementation of the stat_get(P,J) SQL function. This routine is
|
| +** used to query statistical information that has been gathered into
|
| +** the Stat4Accum object by prior calls to stat_push(). The P parameter
|
| +** has type BLOB but it is really just a pointer to the Stat4Accum object.
|
| +** The content to returned is determined by the parameter J
|
| +** which is one of the STAT_GET_xxxx values defined above.
|
| +**
|
| +** If neither STAT3 nor STAT4 are enabled, then J is always
|
| +** STAT_GET_STAT1 and is hence omitted and this routine becomes
|
| +** a one-parameter function, stat_get(P), that always returns the
|
| +** stat1 table entry information.
|
| +*/
|
| +static void statGet(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + /* STAT3 and STAT4 have a parameter on this routine. */
|
| + int eCall = sqlite3_value_int(argv[1]);
|
| + assert( argc==2 );
|
| + assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ
|
| + || eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT
|
| + || eCall==STAT_GET_NDLT
|
| + );
|
| + if( eCall==STAT_GET_STAT1 )
|
| +#else
|
| + assert( argc==1 );
|
| +#endif
|
| + {
|
| + /* Return the value to store in the "stat" column of the sqlite_stat1
|
| + ** table for this index.
|
| + **
|
| + ** The value is a string composed of a list of integers describing
|
| + ** the index. The first integer in the list is the total number of
|
| + ** entries in the index. There is one additional integer in the list
|
| + ** for each indexed column. This additional integer is an estimate of
|
| + ** the number of rows matched by a stabbing query on the index using
|
| + ** a key with the corresponding number of fields. In other words,
|
| + ** if the index is on columns (a,b) and the sqlite_stat1 value is
|
| + ** "100 10 2", then SQLite estimates that:
|
| + **
|
| + ** * the index contains 100 rows,
|
| + ** * "WHERE a=?" matches 10 rows, and
|
| + ** * "WHERE a=? AND b=?" matches 2 rows.
|
| + **
|
| + ** If D is the count of distinct values and K is the total number of
|
| + ** rows, then each estimate is computed as:
|
| + **
|
| + ** I = (K+D-1)/D
|
| + */
|
| + char *z;
|
| + int i;
|
| +
|
| + char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 );
|
| + if( zRet==0 ){
|
| + sqlite3_result_error_nomem(context);
|
| + return;
|
| + }
|
| +
|
| + sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
|
| + z = zRet + sqlite3Strlen30(zRet);
|
| + for(i=0; i<p->nKeyCol; i++){
|
| + u64 nDistinct = p->current.anDLt[i] + 1;
|
| + u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
|
| + sqlite3_snprintf(24, z, " %llu", iVal);
|
| + z += sqlite3Strlen30(z);
|
| + assert( p->current.anEq[i] );
|
| + }
|
| + assert( z[0]=='\0' && z>zRet );
|
| +
|
| + sqlite3_result_text(context, zRet, -1, sqlite3_free);
|
| + }
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + else if( eCall==STAT_GET_ROWID ){
|
| + if( p->iGet<0 ){
|
| + samplePushPrevious(p, 0);
|
| + p->iGet = 0;
|
| + }
|
| + if( p->iGet<p->nSample ){
|
| + Stat4Sample *pS = p->a + p->iGet;
|
| + if( pS->nRowid==0 ){
|
| + sqlite3_result_int64(context, pS->u.iRowid);
|
| + }else{
|
| + sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid,
|
| + SQLITE_TRANSIENT);
|
| + }
|
| + }
|
| + }else{
|
| + tRowcnt *aCnt = 0;
|
| +
|
| + assert( p->iGet<p->nSample );
|
| + switch( eCall ){
|
| + case STAT_GET_NEQ: aCnt = p->a[p->iGet].anEq; break;
|
| + case STAT_GET_NLT: aCnt = p->a[p->iGet].anLt; break;
|
| + default: {
|
| + aCnt = p->a[p->iGet].anDLt;
|
| + p->iGet++;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if( IsStat3 ){
|
| + sqlite3_result_int64(context, (i64)aCnt[0]);
|
| + }else{
|
| + char *zRet = sqlite3MallocZero(p->nCol * 25);
|
| + if( zRet==0 ){
|
| + sqlite3_result_error_nomem(context);
|
| + }else{
|
| + int i;
|
| + char *z = zRet;
|
| + for(i=0; i<p->nCol; i++){
|
| + sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
|
| + z += sqlite3Strlen30(z);
|
| + }
|
| + assert( z[0]=='\0' && z>zRet );
|
| + z[-1] = '\0';
|
| + sqlite3_result_text(context, zRet, -1, sqlite3_free);
|
| + }
|
| + }
|
| + }
|
| +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
| +#ifndef SQLITE_DEBUG
|
| + UNUSED_PARAMETER( argc );
|
| +#endif
|
| +}
|
| +static const FuncDef statGetFuncdef = {
|
| + 1+IsStat34, /* nArg */
|
| + SQLITE_UTF8, /* funcFlags */
|
| + 0, /* pUserData */
|
| + 0, /* pNext */
|
| + statGet, /* xFunc */
|
| + 0, /* xStep */
|
| + 0, /* xFinalize */
|
| + "stat_get", /* zName */
|
| + 0, /* pHash */
|
| + 0 /* pDestructor */
|
| +};
|
| +
|
| +static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
|
| + assert( regOut!=regStat4 && regOut!=regStat4+1 );
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1);
|
| +#elif SQLITE_DEBUG
|
| + assert( iParam==STAT_GET_STAT1 );
|
| +#else
|
| + UNUSED_PARAMETER( iParam );
|
| +#endif
|
| + sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4, regOut);
|
| + sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF);
|
| + sqlite3VdbeChangeP5(v, 1 + IsStat34);
|
| +}
|
| +
|
| +/*
|
| +** Generate code to do an analysis of all indices associated with
|
| +** a single table.
|
| +*/
|
| +static void analyzeOneTable(
|
| + Parse *pParse, /* Parser context */
|
| + Table *pTab, /* Table whose indices are to be analyzed */
|
| + Index *pOnlyIdx, /* If not NULL, only analyze this one index */
|
| + int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */
|
| + int iMem, /* Available memory locations begin here */
|
| + int iTab /* Next available cursor */
|
| +){
|
| + sqlite3 *db = pParse->db; /* Database handle */
|
| + Index *pIdx; /* An index to being analyzed */
|
| + int iIdxCur; /* Cursor open on index being analyzed */
|
| + int iTabCur; /* Table cursor */
|
| + Vdbe *v; /* The virtual machine being built up */
|
| + int i; /* Loop counter */
|
| + int jZeroRows = -1; /* Jump from here if number of rows is zero */
|
| + int iDb; /* Index of database containing pTab */
|
| + u8 needTableCnt = 1; /* True to count the table */
|
| + int regNewRowid = iMem++; /* Rowid for the inserted record */
|
| + int regStat4 = iMem++; /* Register to hold Stat4Accum object */
|
| + int regChng = iMem++; /* Index of changed index field */
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + int regRowid = iMem++; /* Rowid argument passed to stat_push() */
|
| +#endif
|
| + int regTemp = iMem++; /* Temporary use register */
|
| + int regTabname = iMem++; /* Register containing table name */
|
| + int regIdxname = iMem++; /* Register containing index name */
|
| + int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
|
| + int regPrev = iMem; /* MUST BE LAST (see below) */
|
| +
|
| + pParse->nMem = MAX(pParse->nMem, iMem);
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v==0 || NEVER(pTab==0) ){
|
| + return;
|
| + }
|
| + if( pTab->tnum==0 ){
|
| + /* Do not gather statistics on views or virtual tables */
|
| + return;
|
| + }
|
| + if( sqlite3_strlike("sqlite_%", pTab->zName, 0)==0 ){
|
| + /* Do not gather statistics on system tables */
|
| + return;
|
| + }
|
| + assert( sqlite3BtreeHoldsAllMutexes(db) );
|
| + iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| + assert( iDb>=0 );
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
|
| + db->aDb[iDb].zName ) ){
|
| + return;
|
| + }
|
| +#endif
|
| +
|
| + /* Establish a read-lock on the table at the shared-cache level.
|
| + ** Open a read-only cursor on the table. Also allocate a cursor number
|
| + ** to use for scanning indexes (iIdxCur). No index cursor is opened at
|
| + ** this time though. */
|
| + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
| + iTabCur = iTab++;
|
| + iIdxCur = iTab++;
|
| + pParse->nTab = MAX(pParse->nTab, iTab);
|
| + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
|
| + sqlite3VdbeLoadString(v, regTabname, pTab->zName);
|
| +
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + int nCol; /* Number of columns in pIdx. "N" */
|
| + int addrRewind; /* Address of "OP_Rewind iIdxCur" */
|
| + int addrNextRow; /* Address of "next_row:" */
|
| + const char *zIdxName; /* Name of the index */
|
| + int nColTest; /* Number of columns to test for changes */
|
| +
|
| + if( pOnlyIdx && pOnlyIdx!=pIdx ) continue;
|
| + if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0;
|
| + if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIdx) ){
|
| + nCol = pIdx->nKeyCol;
|
| + zIdxName = pTab->zName;
|
| + nColTest = nCol - 1;
|
| + }else{
|
| + nCol = pIdx->nColumn;
|
| + zIdxName = pIdx->zName;
|
| + nColTest = pIdx->uniqNotNull ? pIdx->nKeyCol-1 : nCol-1;
|
| + }
|
| +
|
| + /* Populate the register containing the index name. */
|
| + sqlite3VdbeLoadString(v, regIdxname, zIdxName);
|
| + VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName));
|
| +
|
| + /*
|
| + ** Pseudo-code for loop that calls stat_push():
|
| + **
|
| + ** Rewind csr
|
| + ** if eof(csr) goto end_of_scan;
|
| + ** regChng = 0
|
| + ** goto chng_addr_0;
|
| + **
|
| + ** next_row:
|
| + ** regChng = 0
|
| + ** if( idx(0) != regPrev(0) ) goto chng_addr_0
|
| + ** regChng = 1
|
| + ** if( idx(1) != regPrev(1) ) goto chng_addr_1
|
| + ** ...
|
| + ** regChng = N
|
| + ** goto chng_addr_N
|
| + **
|
| + ** chng_addr_0:
|
| + ** regPrev(0) = idx(0)
|
| + ** chng_addr_1:
|
| + ** regPrev(1) = idx(1)
|
| + ** ...
|
| + **
|
| + ** endDistinctTest:
|
| + ** regRowid = idx(rowid)
|
| + ** stat_push(P, regChng, regRowid)
|
| + ** Next csr
|
| + ** if !eof(csr) goto next_row;
|
| + **
|
| + ** end_of_scan:
|
| + */
|
| +
|
| + /* Make sure there are enough memory cells allocated to accommodate
|
| + ** the regPrev array and a trailing rowid (the rowid slot is required
|
| + ** when building a record to insert into the sample column of
|
| + ** the sqlite_stat4 table. */
|
| + pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
|
| +
|
| + /* Open a read-only cursor on the index being analyzed. */
|
| + assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
|
| + sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb);
|
| + sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
| + VdbeComment((v, "%s", pIdx->zName));
|
| +
|
| + /* Invoke the stat_init() function. The arguments are:
|
| + **
|
| + ** (1) the number of columns in the index including the rowid
|
| + ** (or for a WITHOUT ROWID table, the number of PK columns),
|
| + ** (2) the number of columns in the key without the rowid/pk
|
| + ** (3) the number of rows in the index,
|
| + **
|
| + **
|
| + ** The third argument is only used for STAT3 and STAT4
|
| + */
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
|
| +#endif
|
| + sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
|
| + sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4+1, regStat4);
|
| + sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF);
|
| + sqlite3VdbeChangeP5(v, 2+IsStat34);
|
| +
|
| + /* Implementation of the following:
|
| + **
|
| + ** Rewind csr
|
| + ** if eof(csr) goto end_of_scan;
|
| + ** regChng = 0
|
| + ** goto next_push_0;
|
| + **
|
| + */
|
| + addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
| + VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
|
| + addrNextRow = sqlite3VdbeCurrentAddr(v);
|
| +
|
| + if( nColTest>0 ){
|
| + int endDistinctTest = sqlite3VdbeMakeLabel(v);
|
| + int *aGotoChng; /* Array of jump instruction addresses */
|
| + aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest);
|
| + if( aGotoChng==0 ) continue;
|
| +
|
| + /*
|
| + ** next_row:
|
| + ** regChng = 0
|
| + ** if( idx(0) != regPrev(0) ) goto chng_addr_0
|
| + ** regChng = 1
|
| + ** if( idx(1) != regPrev(1) ) goto chng_addr_1
|
| + ** ...
|
| + ** regChng = N
|
| + ** goto endDistinctTest
|
| + */
|
| + sqlite3VdbeAddOp0(v, OP_Goto);
|
| + addrNextRow = sqlite3VdbeCurrentAddr(v);
|
| + if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){
|
| + /* For a single-column UNIQUE index, once we have found a non-NULL
|
| + ** row, we know that all the rest will be distinct, so skip
|
| + ** subsequent distinctness tests. */
|
| + sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest);
|
| + VdbeCoverage(v);
|
| + }
|
| + for(i=0; i<nColTest; i++){
|
| + char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
|
| + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
|
| + aGotoChng[i] =
|
| + sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
|
| + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
| + VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng);
|
| + sqlite3VdbeGoto(v, endDistinctTest);
|
| +
|
| +
|
| + /*
|
| + ** chng_addr_0:
|
| + ** regPrev(0) = idx(0)
|
| + ** chng_addr_1:
|
| + ** regPrev(1) = idx(1)
|
| + ** ...
|
| + */
|
| + sqlite3VdbeJumpHere(v, addrNextRow-1);
|
| + for(i=0; i<nColTest; i++){
|
| + sqlite3VdbeJumpHere(v, aGotoChng[i]);
|
| + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i);
|
| + }
|
| + sqlite3VdbeResolveLabel(v, endDistinctTest);
|
| + sqlite3DbFree(db, aGotoChng);
|
| + }
|
| +
|
| + /*
|
| + ** chng_addr_N:
|
| + ** regRowid = idx(rowid) // STAT34 only
|
| + ** stat_push(P, regChng, regRowid) // 3rd parameter STAT34 only
|
| + ** Next csr
|
| + ** if !eof(csr) goto next_row;
|
| + */
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + assert( regRowid==(regStat4+2) );
|
| + if( HasRowid(pTab) ){
|
| + sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
|
| + }else{
|
| + Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
| + int j, k, regKey;
|
| + regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
| + for(j=0; j<pPk->nKeyCol; j++){
|
| + k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
|
| + assert( k>=0 && k<pTab->nCol );
|
| + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
| + VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
|
| + sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
|
| + }
|
| +#endif
|
| + assert( regChng==(regStat4+1) );
|
| + sqlite3VdbeAddOp3(v, OP_Function0, 1, regStat4, regTemp);
|
| + sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF);
|
| + sqlite3VdbeChangeP5(v, 2+IsStat34);
|
| + sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
| +
|
| + /* Add the entry to the stat1 table. */
|
| + callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
|
| + assert( "BBB"[0]==SQLITE_AFF_TEXT );
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| +
|
| + /* Add the entries to the stat3 or stat4 table. */
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + {
|
| + int regEq = regStat1;
|
| + int regLt = regStat1+1;
|
| + int regDLt = regStat1+2;
|
| + int regSample = regStat1+3;
|
| + int regCol = regStat1+4;
|
| + int regSampleRowid = regCol + nCol;
|
| + int addrNext;
|
| + int addrIsNull;
|
| + u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
|
| +
|
| + pParse->nMem = MAX(pParse->nMem, regCol+nCol);
|
| +
|
| + addrNext = sqlite3VdbeCurrentAddr(v);
|
| + callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid);
|
| + addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
|
| + VdbeCoverage(v);
|
| + callStatGet(v, regStat4, STAT_GET_NEQ, regEq);
|
| + callStatGet(v, regStat4, STAT_GET_NLT, regLt);
|
| + callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
|
| + sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
|
| + /* We know that the regSampleRowid row exists because it was read by
|
| + ** the previous loop. Thus the not-found jump of seekOp will never
|
| + ** be taken */
|
| + VdbeCoverageNeverTaken(v);
|
| +#ifdef SQLITE_ENABLE_STAT3
|
| + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
|
| +#else
|
| + for(i=0; i<nCol; i++){
|
| + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i);
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
|
| +#endif
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid);
|
| + sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
|
| + sqlite3VdbeJumpHere(v, addrIsNull);
|
| + }
|
| +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
| +
|
| + /* End of analysis */
|
| + sqlite3VdbeJumpHere(v, addrRewind);
|
| + }
|
| +
|
| +
|
| + /* Create a single sqlite_stat1 entry containing NULL as the index
|
| + ** name and the row count as the content.
|
| + */
|
| + if( pOnlyIdx==0 && needTableCnt ){
|
| + VdbeComment((v, "%s", pTab->zName));
|
| + sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1);
|
| + jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
|
| + assert( "BBB"[0]==SQLITE_AFF_TEXT );
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| + sqlite3VdbeJumpHere(v, jZeroRows);
|
| + }
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Generate code that will cause the most recent index analysis to
|
| +** be loaded into internal hash tables where is can be used.
|
| +*/
|
| +static void loadAnalysis(Parse *pParse, int iDb){
|
| + Vdbe *v = sqlite3GetVdbe(pParse);
|
| + if( v ){
|
| + sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Generate code that will do an analysis of an entire database
|
| +*/
|
| +static void analyzeDatabase(Parse *pParse, int iDb){
|
| + sqlite3 *db = pParse->db;
|
| + Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */
|
| + HashElem *k;
|
| + int iStatCur;
|
| + int iMem;
|
| + int iTab;
|
| +
|
| + sqlite3BeginWriteOperation(pParse, 0, iDb);
|
| + iStatCur = pParse->nTab;
|
| + pParse->nTab += 3;
|
| + openStatTable(pParse, iDb, iStatCur, 0, 0);
|
| + iMem = pParse->nMem+1;
|
| + iTab = pParse->nTab;
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
|
| + Table *pTab = (Table*)sqliteHashData(k);
|
| + analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
|
| + }
|
| + loadAnalysis(pParse, iDb);
|
| +}
|
| +
|
| +/*
|
| +** Generate code that will do an analysis of a single table in
|
| +** a database. If pOnlyIdx is not NULL then it is a single index
|
| +** in pTab that should be analyzed.
|
| +*/
|
| +static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){
|
| + int iDb;
|
| + int iStatCur;
|
| +
|
| + assert( pTab!=0 );
|
| + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
| + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
| + sqlite3BeginWriteOperation(pParse, 0, iDb);
|
| + iStatCur = pParse->nTab;
|
| + pParse->nTab += 3;
|
| + if( pOnlyIdx ){
|
| + openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx");
|
| + }else{
|
| + openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl");
|
| + }
|
| + analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,pParse->nTab);
|
| + loadAnalysis(pParse, iDb);
|
| +}
|
| +
|
| +/*
|
| +** Generate code for the ANALYZE command. The parser calls this routine
|
| +** when it recognizes an ANALYZE command.
|
| +**
|
| +** ANALYZE -- 1
|
| +** ANALYZE <database> -- 2
|
| +** ANALYZE ?<database>.?<tablename> -- 3
|
| +**
|
| +** Form 1 causes all indices in all attached databases to be analyzed.
|
| +** Form 2 analyzes all indices the single database named.
|
| +** Form 3 analyzes all indices associated with the named table.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
|
| + sqlite3 *db = pParse->db;
|
| + int iDb;
|
| + int i;
|
| + char *z, *zDb;
|
| + Table *pTab;
|
| + Index *pIdx;
|
| + Token *pTableName;
|
| + Vdbe *v;
|
| +
|
| + /* Read the database schema. If an error occurs, leave an error message
|
| + ** and code in pParse and return NULL. */
|
| + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
| + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
| + return;
|
| + }
|
| +
|
| + assert( pName2!=0 || pName1==0 );
|
| + if( pName1==0 ){
|
| + /* Form 1: Analyze everything */
|
| + for(i=0; i<db->nDb; i++){
|
| + if( i==1 ) continue; /* Do not analyze the TEMP database */
|
| + analyzeDatabase(pParse, i);
|
| + }
|
| + }else if( pName2->n==0 ){
|
| + /* Form 2: Analyze the database or table named */
|
| + iDb = sqlite3FindDb(db, pName1);
|
| + if( iDb>=0 ){
|
| + analyzeDatabase(pParse, iDb);
|
| + }else{
|
| + z = sqlite3NameFromToken(db, pName1);
|
| + if( z ){
|
| + if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){
|
| + analyzeTable(pParse, pIdx->pTable, pIdx);
|
| + }else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){
|
| + analyzeTable(pParse, pTab, 0);
|
| + }
|
| + sqlite3DbFree(db, z);
|
| + }
|
| + }
|
| + }else{
|
| + /* Form 3: Analyze the fully qualified table name */
|
| + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
|
| + if( iDb>=0 ){
|
| + zDb = db->aDb[iDb].zName;
|
| + z = sqlite3NameFromToken(db, pTableName);
|
| + if( z ){
|
| + if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
|
| + analyzeTable(pParse, pIdx->pTable, pIdx);
|
| + }else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){
|
| + analyzeTable(pParse, pTab, 0);
|
| + }
|
| + sqlite3DbFree(db, z);
|
| + }
|
| + }
|
| + }
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
|
| +}
|
| +
|
| +/*
|
| +** Used to pass information from the analyzer reader through to the
|
| +** callback routine.
|
| +*/
|
| +typedef struct analysisInfo analysisInfo;
|
| +struct analysisInfo {
|
| + sqlite3 *db;
|
| + const char *zDatabase;
|
| +};
|
| +
|
| +/*
|
| +** The first argument points to a nul-terminated string containing a
|
| +** list of space separated integers. Read the first nOut of these into
|
| +** the array aOut[].
|
| +*/
|
| +static void decodeIntArray(
|
| + char *zIntArray, /* String containing int array to decode */
|
| + int nOut, /* Number of slots in aOut[] */
|
| + tRowcnt *aOut, /* Store integers here */
|
| + LogEst *aLog, /* Or, if aOut==0, here */
|
| + Index *pIndex /* Handle extra flags for this index, if not NULL */
|
| +){
|
| + char *z = zIntArray;
|
| + int c;
|
| + int i;
|
| + tRowcnt v;
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + if( z==0 ) z = "";
|
| +#else
|
| + assert( z!=0 );
|
| +#endif
|
| + for(i=0; *z && i<nOut; i++){
|
| + v = 0;
|
| + while( (c=z[0])>='0' && c<='9' ){
|
| + v = v*10 + c - '0';
|
| + z++;
|
| + }
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + if( aOut ) aOut[i] = v;
|
| + if( aLog ) aLog[i] = sqlite3LogEst(v);
|
| +#else
|
| + assert( aOut==0 );
|
| + UNUSED_PARAMETER(aOut);
|
| + assert( aLog!=0 );
|
| + aLog[i] = sqlite3LogEst(v);
|
| +#endif
|
| + if( *z==' ' ) z++;
|
| + }
|
| +#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + assert( pIndex!=0 ); {
|
| +#else
|
| + if( pIndex ){
|
| +#endif
|
| + pIndex->bUnordered = 0;
|
| + pIndex->noSkipScan = 0;
|
| + while( z[0] ){
|
| + if( sqlite3_strglob("unordered*", z)==0 ){
|
| + pIndex->bUnordered = 1;
|
| + }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
|
| + pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
|
| + }else if( sqlite3_strglob("noskipscan*", z)==0 ){
|
| + pIndex->noSkipScan = 1;
|
| + }
|
| +#ifdef SQLITE_ENABLE_COSTMULT
|
| + else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
|
| + pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
|
| + }
|
| +#endif
|
| + while( z[0]!=0 && z[0]!=' ' ) z++;
|
| + while( z[0]==' ' ) z++;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This callback is invoked once for each index when reading the
|
| +** sqlite_stat1 table.
|
| +**
|
| +** argv[0] = name of the table
|
| +** argv[1] = name of the index (might be NULL)
|
| +** argv[2] = results of analysis - on integer for each column
|
| +**
|
| +** Entries for which argv[1]==NULL simply record the number of rows in
|
| +** the table.
|
| +*/
|
| +static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
| + analysisInfo *pInfo = (analysisInfo*)pData;
|
| + Index *pIndex;
|
| + Table *pTable;
|
| + const char *z;
|
| +
|
| + assert( argc==3 );
|
| + UNUSED_PARAMETER2(NotUsed, argc);
|
| +
|
| + if( argv==0 || argv[0]==0 || argv[2]==0 ){
|
| + return 0;
|
| + }
|
| + pTable = sqlite3FindTable(pInfo->db, argv[0], pInfo->zDatabase);
|
| + if( pTable==0 ){
|
| + return 0;
|
| + }
|
| + if( argv[1]==0 ){
|
| + pIndex = 0;
|
| + }else if( sqlite3_stricmp(argv[0],argv[1])==0 ){
|
| + pIndex = sqlite3PrimaryKeyIndex(pTable);
|
| + }else{
|
| + pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
|
| + }
|
| + z = argv[2];
|
| +
|
| + if( pIndex ){
|
| + tRowcnt *aiRowEst = 0;
|
| + int nCol = pIndex->nKeyCol+1;
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + /* Index.aiRowEst may already be set here if there are duplicate
|
| + ** sqlite_stat1 entries for this index. In that case just clobber
|
| + ** the old data with the new instead of allocating a new array. */
|
| + if( pIndex->aiRowEst==0 ){
|
| + pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol);
|
| + if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1;
|
| + }
|
| + aiRowEst = pIndex->aiRowEst;
|
| +#endif
|
| + pIndex->bUnordered = 0;
|
| + decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex);
|
| + if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
|
| + }else{
|
| + Index fakeIdx;
|
| + fakeIdx.szIdxRow = pTable->szTabRow;
|
| +#ifdef SQLITE_ENABLE_COSTMULT
|
| + fakeIdx.pTable = pTable;
|
| +#endif
|
| + decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
|
| + pTable->szTabRow = fakeIdx.szIdxRow;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** If the Index.aSample variable is not NULL, delete the aSample[] array
|
| +** and its contents.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + if( pIdx->aSample ){
|
| + int j;
|
| + for(j=0; j<pIdx->nSample; j++){
|
| + IndexSample *p = &pIdx->aSample[j];
|
| + sqlite3DbFree(db, p->p);
|
| + }
|
| + sqlite3DbFree(db, pIdx->aSample);
|
| + }
|
| + if( db && db->pnBytesFreed==0 ){
|
| + pIdx->nSample = 0;
|
| + pIdx->aSample = 0;
|
| + }
|
| +#else
|
| + UNUSED_PARAMETER(db);
|
| + UNUSED_PARAMETER(pIdx);
|
| +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
| +}
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| +/*
|
| +** Populate the pIdx->aAvgEq[] array based on the samples currently
|
| +** stored in pIdx->aSample[].
|
| +*/
|
| +static void initAvgEq(Index *pIdx){
|
| + if( pIdx ){
|
| + IndexSample *aSample = pIdx->aSample;
|
| + IndexSample *pFinal = &aSample[pIdx->nSample-1];
|
| + int iCol;
|
| + int nCol = 1;
|
| + if( pIdx->nSampleCol>1 ){
|
| + /* If this is stat4 data, then calculate aAvgEq[] values for all
|
| + ** sample columns except the last. The last is always set to 1, as
|
| + ** once the trailing PK fields are considered all index keys are
|
| + ** unique. */
|
| + nCol = pIdx->nSampleCol-1;
|
| + pIdx->aAvgEq[nCol] = 1;
|
| + }
|
| + for(iCol=0; iCol<nCol; iCol++){
|
| + int nSample = pIdx->nSample;
|
| + int i; /* Used to iterate through samples */
|
| + tRowcnt sumEq = 0; /* Sum of the nEq values */
|
| + tRowcnt avgEq = 0;
|
| + tRowcnt nRow; /* Number of rows in index */
|
| + i64 nSum100 = 0; /* Number of terms contributing to sumEq */
|
| + i64 nDist100; /* Number of distinct values in index */
|
| +
|
| + if( !pIdx->aiRowEst || iCol>=pIdx->nKeyCol || pIdx->aiRowEst[iCol+1]==0 ){
|
| + nRow = pFinal->anLt[iCol];
|
| + nDist100 = (i64)100 * pFinal->anDLt[iCol];
|
| + nSample--;
|
| + }else{
|
| + nRow = pIdx->aiRowEst[0];
|
| + nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1];
|
| + }
|
| + pIdx->nRowEst0 = nRow;
|
| +
|
| + /* Set nSum to the number of distinct (iCol+1) field prefixes that
|
| + ** occur in the stat4 table for this index. Set sumEq to the sum of
|
| + ** the nEq values for column iCol for the same set (adding the value
|
| + ** only once where there exist duplicate prefixes). */
|
| + for(i=0; i<nSample; i++){
|
| + if( i==(pIdx->nSample-1)
|
| + || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol]
|
| + ){
|
| + sumEq += aSample[i].anEq[iCol];
|
| + nSum100 += 100;
|
| + }
|
| + }
|
| +
|
| + if( nDist100>nSum100 ){
|
| + avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100);
|
| + }
|
| + if( avgEq==0 ) avgEq = 1;
|
| + pIdx->aAvgEq[iCol] = avgEq;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Look up an index by name. Or, if the name of a WITHOUT ROWID table
|
| +** is supplied instead, find the PRIMARY KEY index for that table.
|
| +*/
|
| +static Index *findIndexOrPrimaryKey(
|
| + sqlite3 *db,
|
| + const char *zName,
|
| + const char *zDb
|
| +){
|
| + Index *pIdx = sqlite3FindIndex(db, zName, zDb);
|
| + if( pIdx==0 ){
|
| + Table *pTab = sqlite3FindTable(db, zName, zDb);
|
| + if( pTab && !HasRowid(pTab) ) pIdx = sqlite3PrimaryKeyIndex(pTab);
|
| + }
|
| + return pIdx;
|
| +}
|
| +
|
| +/*
|
| +** Load the content from either the sqlite_stat4 or sqlite_stat3 table
|
| +** into the relevant Index.aSample[] arrays.
|
| +**
|
| +** Arguments zSql1 and zSql2 must point to SQL statements that return
|
| +** data equivalent to the following (statements are different for stat3,
|
| +** see the caller of this function for details):
|
| +**
|
| +** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx
|
| +** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4
|
| +**
|
| +** where %Q is replaced with the database name before the SQL is executed.
|
| +*/
|
| +static int loadStatTbl(
|
| + sqlite3 *db, /* Database handle */
|
| + int bStat3, /* Assume single column records only */
|
| + const char *zSql1, /* SQL statement 1 (see above) */
|
| + const char *zSql2, /* SQL statement 2 (see above) */
|
| + const char *zDb /* Database name (e.g. "main") */
|
| +){
|
| + int rc; /* Result codes from subroutines */
|
| + sqlite3_stmt *pStmt = 0; /* An SQL statement being run */
|
| + char *zSql; /* Text of the SQL statement */
|
| + Index *pPrevIdx = 0; /* Previous index in the loop */
|
| + IndexSample *pSample; /* A slot in pIdx->aSample[] */
|
| +
|
| + assert( db->lookaside.bEnabled==0 );
|
| + zSql = sqlite3MPrintf(db, zSql1, zDb);
|
| + if( !zSql ){
|
| + return SQLITE_NOMEM;
|
| + }
|
| + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
| + sqlite3DbFree(db, zSql);
|
| + if( rc ) return rc;
|
| +
|
| + while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
| + int nIdxCol = 1; /* Number of columns in stat4 records */
|
| +
|
| + char *zIndex; /* Index name */
|
| + Index *pIdx; /* Pointer to the index object */
|
| + int nSample; /* Number of samples */
|
| + int nByte; /* Bytes of space required */
|
| + int i; /* Bytes of space required */
|
| + tRowcnt *pSpace;
|
| +
|
| + zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
| + if( zIndex==0 ) continue;
|
| + nSample = sqlite3_column_int(pStmt, 1);
|
| + pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
|
| + assert( pIdx==0 || bStat3 || pIdx->nSample==0 );
|
| + /* Index.nSample is non-zero at this point if data has already been
|
| + ** loaded from the stat4 table. In this case ignore stat3 data. */
|
| + if( pIdx==0 || pIdx->nSample ) continue;
|
| + if( bStat3==0 ){
|
| + assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
|
| + if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
|
| + nIdxCol = pIdx->nKeyCol;
|
| + }else{
|
| + nIdxCol = pIdx->nColumn;
|
| + }
|
| + }
|
| + pIdx->nSampleCol = nIdxCol;
|
| + nByte = sizeof(IndexSample) * nSample;
|
| + nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
|
| + nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
|
| +
|
| + pIdx->aSample = sqlite3DbMallocZero(db, nByte);
|
| + if( pIdx->aSample==0 ){
|
| + sqlite3_finalize(pStmt);
|
| + return SQLITE_NOMEM;
|
| + }
|
| + pSpace = (tRowcnt*)&pIdx->aSample[nSample];
|
| + pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
|
| + for(i=0; i<nSample; i++){
|
| + pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
|
| + pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
|
| + pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol;
|
| + }
|
| + assert( ((u8*)pSpace)-nByte==(u8*)(pIdx->aSample) );
|
| + }
|
| + rc = sqlite3_finalize(pStmt);
|
| + if( rc ) return rc;
|
| +
|
| + zSql = sqlite3MPrintf(db, zSql2, zDb);
|
| + if( !zSql ){
|
| + return SQLITE_NOMEM;
|
| + }
|
| + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
| + sqlite3DbFree(db, zSql);
|
| + if( rc ) return rc;
|
| +
|
| + while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
| + char *zIndex; /* Index name */
|
| + Index *pIdx; /* Pointer to the index object */
|
| + int nCol = 1; /* Number of columns in index */
|
| +
|
| + zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
| + if( zIndex==0 ) continue;
|
| + pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
|
| + if( pIdx==0 ) continue;
|
| + /* This next condition is true if data has already been loaded from
|
| + ** the sqlite_stat4 table. In this case ignore stat3 data. */
|
| + nCol = pIdx->nSampleCol;
|
| + if( bStat3 && nCol>1 ) continue;
|
| + if( pIdx!=pPrevIdx ){
|
| + initAvgEq(pPrevIdx);
|
| + pPrevIdx = pIdx;
|
| + }
|
| + pSample = &pIdx->aSample[pIdx->nSample];
|
| + decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0);
|
| + decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0);
|
| + decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0);
|
| +
|
| + /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer.
|
| + ** This is in case the sample record is corrupted. In that case, the
|
| + ** sqlite3VdbeRecordCompare() may read up to two varints past the
|
| + ** end of the allocated buffer before it realizes it is dealing with
|
| + ** a corrupt record. Adding the two 0x00 bytes prevents this from causing
|
| + ** a buffer overread. */
|
| + pSample->n = sqlite3_column_bytes(pStmt, 4);
|
| + pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
|
| + if( pSample->p==0 ){
|
| + sqlite3_finalize(pStmt);
|
| + return SQLITE_NOMEM;
|
| + }
|
| + memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
|
| + pIdx->nSample++;
|
| + }
|
| + rc = sqlite3_finalize(pStmt);
|
| + if( rc==SQLITE_OK ) initAvgEq(pPrevIdx);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Load content from the sqlite_stat4 and sqlite_stat3 tables into
|
| +** the Index.aSample[] arrays of all indices.
|
| +*/
|
| +static int loadStat4(sqlite3 *db, const char *zDb){
|
| + int rc = SQLITE_OK; /* Result codes from subroutines */
|
| +
|
| + assert( db->lookaside.bEnabled==0 );
|
| + if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
|
| + rc = loadStatTbl(db, 0,
|
| + "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
|
| + "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
|
| + zDb
|
| + );
|
| + }
|
| +
|
| + if( rc==SQLITE_OK && sqlite3FindTable(db, "sqlite_stat3", zDb) ){
|
| + rc = loadStatTbl(db, 1,
|
| + "SELECT idx,count(*) FROM %Q.sqlite_stat3 GROUP BY idx",
|
| + "SELECT idx,neq,nlt,ndlt,sqlite_record(sample) FROM %Q.sqlite_stat3",
|
| + zDb
|
| + );
|
| + }
|
| +
|
| + return rc;
|
| +}
|
| +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
| +
|
| +/*
|
| +** Load the content of the sqlite_stat1 and sqlite_stat3/4 tables. The
|
| +** contents of sqlite_stat1 are used to populate the Index.aiRowEst[]
|
| +** arrays. The contents of sqlite_stat3/4 are used to populate the
|
| +** Index.aSample[] arrays.
|
| +**
|
| +** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR
|
| +** is returned. In this case, even if SQLITE_ENABLE_STAT3/4 was defined
|
| +** during compilation and the sqlite_stat3/4 table is present, no data is
|
| +** read from it.
|
| +**
|
| +** If SQLITE_ENABLE_STAT3/4 was defined during compilation and the
|
| +** sqlite_stat4 table is not present in the database, SQLITE_ERROR is
|
| +** returned. However, in this case, data is read from the sqlite_stat1
|
| +** table (if it is present) before returning.
|
| +**
|
| +** If an OOM error occurs, this function always sets db->mallocFailed.
|
| +** This means if the caller does not care about other errors, the return
|
| +** code may be ignored.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
| + analysisInfo sInfo;
|
| + HashElem *i;
|
| + char *zSql;
|
| + int rc;
|
| +
|
| + assert( iDb>=0 && iDb<db->nDb );
|
| + assert( db->aDb[iDb].pBt!=0 );
|
| +
|
| + /* Clear any prior statistics */
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
|
| + Index *pIdx = sqliteHashData(i);
|
| + sqlite3DefaultRowEst(pIdx);
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + sqlite3DeleteIndexSamples(db, pIdx);
|
| + pIdx->aSample = 0;
|
| +#endif
|
| + }
|
| +
|
| + /* Check to make sure the sqlite_stat1 table exists */
|
| + sInfo.db = db;
|
| + sInfo.zDatabase = db->aDb[iDb].zName;
|
| + if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
|
| + return SQLITE_ERROR;
|
| + }
|
| +
|
| + /* Load new statistics out of the sqlite_stat1 table */
|
| + zSql = sqlite3MPrintf(db,
|
| + "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
|
| + if( zSql==0 ){
|
| + rc = SQLITE_NOMEM;
|
| + }else{
|
| + rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
|
| + sqlite3DbFree(db, zSql);
|
| + }
|
| +
|
| +
|
| + /* Load the statistics from the sqlite_stat4 table. */
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
|
| + int lookasideEnabled = db->lookaside.bEnabled;
|
| + db->lookaside.bEnabled = 0;
|
| + rc = loadStat4(db, sInfo.zDatabase);
|
| + db->lookaside.bEnabled = lookasideEnabled;
|
| + }
|
| + for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
|
| + Index *pIdx = sqliteHashData(i);
|
| + sqlite3_free(pIdx->aiRowEst);
|
| + pIdx->aiRowEst = 0;
|
| + }
|
| +#endif
|
| +
|
| + if( rc==SQLITE_NOMEM ){
|
| + db->mallocFailed = 1;
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +
|
| +#endif /* SQLITE_OMIT_ANALYZE */
|
| +
|
| +/************** End of analyze.c *********************************************/
|
| +/************** Begin file attach.c ******************************************/
|
| +/*
|
| +** 2003 April 6
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains code used to implement the ATTACH and DETACH commands.
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +#ifndef SQLITE_OMIT_ATTACH
|
| +/*
|
| +** Resolve an expression that was part of an ATTACH or DETACH statement. This
|
| +** is slightly different from resolving a normal SQL expression, because simple
|
| +** identifiers are treated as strings, not possible column names or aliases.
|
| +**
|
| +** i.e. if the parser sees:
|
| +**
|
| +** ATTACH DATABASE abc AS def
|
| +**
|
| +** it treats the two expressions as literal strings 'abc' and 'def' instead of
|
| +** looking for columns of the same name.
|
| +**
|
| +** This only applies to the root node of pExpr, so the statement:
|
| +**
|
| +** ATTACH DATABASE abc||def AS 'db2'
|
| +**
|
| +** will fail because neither abc or def can be resolved.
|
| +*/
|
| +static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
|
| +{
|
| + int rc = SQLITE_OK;
|
| + if( pExpr ){
|
| + if( pExpr->op!=TK_ID ){
|
| + rc = sqlite3ResolveExprNames(pName, pExpr);
|
| + }else{
|
| + pExpr->op = TK_STRING;
|
| + }
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** An SQL user-function registered to do the work of an ATTACH statement. The
|
| +** three arguments to the function come directly from an attach statement:
|
| +**
|
| +** ATTACH DATABASE x AS y KEY z
|
| +**
|
| +** SELECT sqlite_attach(x, y, z)
|
| +**
|
| +** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
|
| +** third argument.
|
| +*/
|
| +static void attachFunc(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **argv
|
| +){
|
| + int i;
|
| + int rc = 0;
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + const char *zName;
|
| + const char *zFile;
|
| + char *zPath = 0;
|
| + char *zErr = 0;
|
| + unsigned int flags;
|
| + Db *aNew;
|
| + char *zErrDyn = 0;
|
| + sqlite3_vfs *pVfs;
|
| +
|
| + UNUSED_PARAMETER(NotUsed);
|
| +
|
| + zFile = (const char *)sqlite3_value_text(argv[0]);
|
| + zName = (const char *)sqlite3_value_text(argv[1]);
|
| + if( zFile==0 ) zFile = "";
|
| + if( zName==0 ) zName = "";
|
| +
|
| + /* Check for the following errors:
|
| + **
|
| + ** * Too many attached databases,
|
| + ** * Transaction currently open
|
| + ** * Specified database name already being used.
|
| + */
|
| + if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
|
| + zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d",
|
| + db->aLimit[SQLITE_LIMIT_ATTACHED]
|
| + );
|
| + goto attach_error;
|
| + }
|
| + if( !db->autoCommit ){
|
| + zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
|
| + goto attach_error;
|
| + }
|
| + for(i=0; i<db->nDb; i++){
|
| + char *z = db->aDb[i].zName;
|
| + assert( z && zName );
|
| + if( sqlite3StrICmp(z, zName)==0 ){
|
| + zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
|
| + goto attach_error;
|
| + }
|
| + }
|
| +
|
| + /* Allocate the new entry in the db->aDb[] array and initialize the schema
|
| + ** hash tables.
|
| + */
|
| + if( db->aDb==db->aDbStatic ){
|
| + aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 );
|
| + if( aNew==0 ) return;
|
| + memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
|
| + }else{
|
| + aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
|
| + if( aNew==0 ) return;
|
| + }
|
| + db->aDb = aNew;
|
| + aNew = &db->aDb[db->nDb];
|
| + memset(aNew, 0, sizeof(*aNew));
|
| +
|
| + /* Open the database file. If the btree is successfully opened, use
|
| + ** it to obtain the database schema. At this point the schema may
|
| + ** or may not be initialized.
|
| + */
|
| + flags = db->openFlags;
|
| + rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
|
| + if( rc!=SQLITE_OK ){
|
| + if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
| + sqlite3_result_error(context, zErr, -1);
|
| + sqlite3_free(zErr);
|
| + return;
|
| + }
|
| + assert( pVfs );
|
| + flags |= SQLITE_OPEN_MAIN_DB;
|
| + rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
|
| + sqlite3_free( zPath );
|
| + db->nDb++;
|
| + if( rc==SQLITE_CONSTRAINT ){
|
| + rc = SQLITE_ERROR;
|
| + zErrDyn = sqlite3MPrintf(db, "database is already attached");
|
| + }else if( rc==SQLITE_OK ){
|
| + Pager *pPager;
|
| + aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
|
| + if( !aNew->pSchema ){
|
| + rc = SQLITE_NOMEM;
|
| + }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
|
| + zErrDyn = sqlite3MPrintf(db,
|
| + "attached databases must use the same text encoding as main database");
|
| + rc = SQLITE_ERROR;
|
| + }
|
| + sqlite3BtreeEnter(aNew->pBt);
|
| + pPager = sqlite3BtreePager(aNew->pBt);
|
| + sqlite3PagerLockingMode(pPager, db->dfltLockMode);
|
| + sqlite3BtreeSecureDelete(aNew->pBt,
|
| + sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
|
| +#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
| + sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
|
| +#endif
|
| + sqlite3BtreeLeave(aNew->pBt);
|
| + }
|
| + aNew->safety_level = 3;
|
| + aNew->zName = sqlite3DbStrDup(db, zName);
|
| + if( rc==SQLITE_OK && aNew->zName==0 ){
|
| + rc = SQLITE_NOMEM;
|
| + }
|
| +
|
| +
|
| +#ifdef SQLITE_HAS_CODEC
|
| + if( rc==SQLITE_OK ){
|
| + extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
|
| + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
| + int nKey;
|
| + char *zKey;
|
| + int t = sqlite3_value_type(argv[2]);
|
| + switch( t ){
|
| + case SQLITE_INTEGER:
|
| + case SQLITE_FLOAT:
|
| + zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
|
| + rc = SQLITE_ERROR;
|
| + break;
|
| +
|
| + case SQLITE_TEXT:
|
| + case SQLITE_BLOB:
|
| + nKey = sqlite3_value_bytes(argv[2]);
|
| + zKey = (char *)sqlite3_value_blob(argv[2]);
|
| + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
| + break;
|
| +
|
| + case SQLITE_NULL:
|
| + /* No key specified. Use the key from the main database */
|
| + sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
| + if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
|
| + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* If the file was opened successfully, read the schema for the new database.
|
| + ** If this fails, or if opening the file failed, then close the file and
|
| + ** remove the entry from the db->aDb[] array. i.e. put everything back the way
|
| + ** we found it.
|
| + */
|
| + if( rc==SQLITE_OK ){
|
| + sqlite3BtreeEnterAll(db);
|
| + rc = sqlite3Init(db, &zErrDyn);
|
| + sqlite3BtreeLeaveAll(db);
|
| + }
|
| +#ifdef SQLITE_USER_AUTHENTICATION
|
| + if( rc==SQLITE_OK ){
|
| + u8 newAuth = 0;
|
| + rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
|
| + if( newAuth<db->auth.authLevel ){
|
| + rc = SQLITE_AUTH_USER;
|
| + }
|
| + }
|
| +#endif
|
| + if( rc ){
|
| + int iDb = db->nDb - 1;
|
| + assert( iDb>=2 );
|
| + if( db->aDb[iDb].pBt ){
|
| + sqlite3BtreeClose(db->aDb[iDb].pBt);
|
| + db->aDb[iDb].pBt = 0;
|
| + db->aDb[iDb].pSchema = 0;
|
| + }
|
| + sqlite3ResetAllSchemasOfConnection(db);
|
| + db->nDb = iDb;
|
| + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
| + db->mallocFailed = 1;
|
| + sqlite3DbFree(db, zErrDyn);
|
| + zErrDyn = sqlite3MPrintf(db, "out of memory");
|
| + }else if( zErrDyn==0 ){
|
| + zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
|
| + }
|
| + goto attach_error;
|
| + }
|
| +
|
| + return;
|
| +
|
| +attach_error:
|
| + /* Return an error if we get here */
|
| + if( zErrDyn ){
|
| + sqlite3_result_error(context, zErrDyn, -1);
|
| + sqlite3DbFree(db, zErrDyn);
|
| + }
|
| + if( rc ) sqlite3_result_error_code(context, rc);
|
| +}
|
| +
|
| +/*
|
| +** An SQL user-function registered to do the work of an DETACH statement. The
|
| +** three arguments to the function come directly from a detach statement:
|
| +**
|
| +** DETACH DATABASE x
|
| +**
|
| +** SELECT sqlite_detach(x)
|
| +*/
|
| +static void detachFunc(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **argv
|
| +){
|
| + const char *zName = (const char *)sqlite3_value_text(argv[0]);
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + int i;
|
| + Db *pDb = 0;
|
| + char zErr[128];
|
| +
|
| + UNUSED_PARAMETER(NotUsed);
|
| +
|
| + if( zName==0 ) zName = "";
|
| + for(i=0; i<db->nDb; i++){
|
| + pDb = &db->aDb[i];
|
| + if( pDb->pBt==0 ) continue;
|
| + if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
|
| + }
|
| +
|
| + if( i>=db->nDb ){
|
| + sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName);
|
| + goto detach_error;
|
| + }
|
| + if( i<2 ){
|
| + sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
|
| + goto detach_error;
|
| + }
|
| + if( !db->autoCommit ){
|
| + sqlite3_snprintf(sizeof(zErr), zErr,
|
| + "cannot DETACH database within transaction");
|
| + goto detach_error;
|
| + }
|
| + if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
|
| + sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
|
| + goto detach_error;
|
| + }
|
| +
|
| + sqlite3BtreeClose(pDb->pBt);
|
| + pDb->pBt = 0;
|
| + pDb->pSchema = 0;
|
| + sqlite3CollapseDatabaseArray(db);
|
| + return;
|
| +
|
| +detach_error:
|
| + sqlite3_result_error(context, zErr, -1);
|
| +}
|
| +
|
| +/*
|
| +** This procedure generates VDBE code for a single invocation of either the
|
| +** sqlite_detach() or sqlite_attach() SQL user functions.
|
| +*/
|
| +static void codeAttach(
|
| + Parse *pParse, /* The parser context */
|
| + int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
|
| + FuncDef const *pFunc,/* FuncDef wrapper for detachFunc() or attachFunc() */
|
| + Expr *pAuthArg, /* Expression to pass to authorization callback */
|
| + Expr *pFilename, /* Name of database file */
|
| + Expr *pDbname, /* Name of the database to use internally */
|
| + Expr *pKey /* Database key for encryption extension */
|
| +){
|
| + int rc;
|
| + NameContext sName;
|
| + Vdbe *v;
|
| + sqlite3* db = pParse->db;
|
| + int regArgs;
|
| +
|
| + memset(&sName, 0, sizeof(NameContext));
|
| + sName.pParse = pParse;
|
| +
|
| + if(
|
| + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
|
| + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
|
| + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
|
| + ){
|
| + goto attach_end;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + if( pAuthArg ){
|
| + char *zAuthArg;
|
| + if( pAuthArg->op==TK_STRING ){
|
| + zAuthArg = pAuthArg->u.zToken;
|
| + }else{
|
| + zAuthArg = 0;
|
| + }
|
| + rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
|
| + if(rc!=SQLITE_OK ){
|
| + goto attach_end;
|
| + }
|
| + }
|
| +#endif /* SQLITE_OMIT_AUTHORIZATION */
|
| +
|
| +
|
| + v = sqlite3GetVdbe(pParse);
|
| + regArgs = sqlite3GetTempRange(pParse, 4);
|
| + sqlite3ExprCode(pParse, pFilename, regArgs);
|
| + sqlite3ExprCode(pParse, pDbname, regArgs+1);
|
| + sqlite3ExprCode(pParse, pKey, regArgs+2);
|
| +
|
| + assert( v || db->mallocFailed );
|
| + if( v ){
|
| + sqlite3VdbeAddOp3(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3);
|
| + assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
|
| + sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
|
| + sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
|
| +
|
| + /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
|
| + ** statement only). For DETACH, set it to false (expire all existing
|
| + ** statements).
|
| + */
|
| + sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH));
|
| + }
|
| +
|
| +attach_end:
|
| + sqlite3ExprDelete(db, pFilename);
|
| + sqlite3ExprDelete(db, pDbname);
|
| + sqlite3ExprDelete(db, pKey);
|
| +}
|
| +
|
| +/*
|
| +** Called by the parser to compile a DETACH statement.
|
| +**
|
| +** DETACH pDbname
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
|
| + static const FuncDef detach_func = {
|
| + 1, /* nArg */
|
| + SQLITE_UTF8, /* funcFlags */
|
| + 0, /* pUserData */
|
| + 0, /* pNext */
|
| + detachFunc, /* xFunc */
|
| + 0, /* xStep */
|
| + 0, /* xFinalize */
|
| + "sqlite_detach", /* zName */
|
| + 0, /* pHash */
|
| + 0 /* pDestructor */
|
| + };
|
| + codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
|
| +}
|
| +
|
| +/*
|
| +** Called by the parser to compile an ATTACH statement.
|
| +**
|
| +** ATTACH p AS pDbname KEY pKey
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
|
| + static const FuncDef attach_func = {
|
| + 3, /* nArg */
|
| + SQLITE_UTF8, /* funcFlags */
|
| + 0, /* pUserData */
|
| + 0, /* pNext */
|
| + attachFunc, /* xFunc */
|
| + 0, /* xStep */
|
| + 0, /* xFinalize */
|
| + "sqlite_attach", /* zName */
|
| + 0, /* pHash */
|
| + 0 /* pDestructor */
|
| + };
|
| + codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
|
| +}
|
| +#endif /* SQLITE_OMIT_ATTACH */
|
| +
|
| +/*
|
| +** Initialize a DbFixer structure. This routine must be called prior
|
| +** to passing the structure to one of the sqliteFixAAAA() routines below.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3FixInit(
|
| + DbFixer *pFix, /* The fixer to be initialized */
|
| + Parse *pParse, /* Error messages will be written here */
|
| + int iDb, /* This is the database that must be used */
|
| + const char *zType, /* "view", "trigger", or "index" */
|
| + const Token *pName /* Name of the view, trigger, or index */
|
| +){
|
| + sqlite3 *db;
|
| +
|
| + db = pParse->db;
|
| + assert( db->nDb>iDb );
|
| + pFix->pParse = pParse;
|
| + pFix->zDb = db->aDb[iDb].zName;
|
| + pFix->pSchema = db->aDb[iDb].pSchema;
|
| + pFix->zType = zType;
|
| + pFix->pName = pName;
|
| + pFix->bVarOnly = (iDb==1);
|
| +}
|
| +
|
| +/*
|
| +** The following set of routines walk through the parse tree and assign
|
| +** a specific database to all table references where the database name
|
| +** was left unspecified in the original SQL statement. The pFix structure
|
| +** must have been initialized by a prior call to sqlite3FixInit().
|
| +**
|
| +** These routines are used to make sure that an index, trigger, or
|
| +** view in one database does not refer to objects in a different database.
|
| +** (Exception: indices, triggers, and views in the TEMP database are
|
| +** allowed to refer to anything.) If a reference is explicitly made
|
| +** to an object in a different database, an error message is added to
|
| +** pParse->zErrMsg and these routines return non-zero. If everything
|
| +** checks out, these routines return 0.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3FixSrcList(
|
| + DbFixer *pFix, /* Context of the fixation */
|
| + SrcList *pList /* The Source list to check and modify */
|
| +){
|
| + int i;
|
| + const char *zDb;
|
| + struct SrcList_item *pItem;
|
| +
|
| + if( NEVER(pList==0) ) return 0;
|
| + zDb = pFix->zDb;
|
| + for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
| + if( pFix->bVarOnly==0 ){
|
| + if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
|
| + sqlite3ErrorMsg(pFix->pParse,
|
| + "%s %T cannot reference objects in database %s",
|
| + pFix->zType, pFix->pName, pItem->zDatabase);
|
| + return 1;
|
| + }
|
| + sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
|
| + pItem->zDatabase = 0;
|
| + pItem->pSchema = pFix->pSchema;
|
| + }
|
| +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
| + if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
|
| + if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
|
| +#endif
|
| + }
|
| + return 0;
|
| +}
|
| +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
| +SQLITE_PRIVATE int sqlite3FixSelect(
|
| + DbFixer *pFix, /* Context of the fixation */
|
| + Select *pSelect /* The SELECT statement to be fixed to one database */
|
| +){
|
| + while( pSelect ){
|
| + if( sqlite3FixExprList(pFix, pSelect->pEList) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixExpr(pFix, pSelect->pOffset) ){
|
| + return 1;
|
| + }
|
| + pSelect = pSelect->pPrior;
|
| + }
|
| + return 0;
|
| +}
|
| +SQLITE_PRIVATE int sqlite3FixExpr(
|
| + DbFixer *pFix, /* Context of the fixation */
|
| + Expr *pExpr /* The expression to be fixed to one database */
|
| +){
|
| + while( pExpr ){
|
| + if( pExpr->op==TK_VARIABLE ){
|
| + if( pFix->pParse->db->init.busy ){
|
| + pExpr->op = TK_NULL;
|
| + }else{
|
| + sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
|
| + return 1;
|
| + }
|
| + }
|
| + if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
|
| + if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
| + if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
|
| + }else{
|
| + if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
|
| + }
|
| + if( sqlite3FixExpr(pFix, pExpr->pRight) ){
|
| + return 1;
|
| + }
|
| + pExpr = pExpr->pLeft;
|
| + }
|
| + return 0;
|
| +}
|
| +SQLITE_PRIVATE int sqlite3FixExprList(
|
| + DbFixer *pFix, /* Context of the fixation */
|
| + ExprList *pList /* The expression to be fixed to one database */
|
| +){
|
| + int i;
|
| + struct ExprList_item *pItem;
|
| + if( pList==0 ) return 0;
|
| + for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
|
| + if( sqlite3FixExpr(pFix, pItem->pExpr) ){
|
| + return 1;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +#endif
|
| +
|
| +#ifndef SQLITE_OMIT_TRIGGER
|
| +SQLITE_PRIVATE int sqlite3FixTriggerStep(
|
| + DbFixer *pFix, /* Context of the fixation */
|
| + TriggerStep *pStep /* The trigger step be fixed to one database */
|
| +){
|
| + while( pStep ){
|
| + if( sqlite3FixSelect(pFix, pStep->pSelect) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixExpr(pFix, pStep->pWhere) ){
|
| + return 1;
|
| + }
|
| + if( sqlite3FixExprList(pFix, pStep->pExprList) ){
|
| + return 1;
|
| + }
|
| + pStep = pStep->pNext;
|
| + }
|
| + return 0;
|
| +}
|
| +#endif
|
| +
|
| +/************** End of attach.c **********************************************/
|
| +/************** Begin file auth.c ********************************************/
|
| +/*
|
| +** 2003 January 11
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains code used to implement the sqlite3_set_authorizer()
|
| +** API. This facility is an optional feature of the library. Embedded
|
| +** systems that do not need this facility may omit it by recompiling
|
| +** the library with -DSQLITE_OMIT_AUTHORIZATION=1
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +/*
|
| +** All of the code in this file may be omitted by defining a single
|
| +** macro.
|
| +*/
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| +
|
| +/*
|
| +** Set or clear the access authorization function.
|
| +**
|
| +** The access authorization function is be called during the compilation
|
| +** phase to verify that the user has read and/or write access permission on
|
| +** various fields of the database. The first argument to the auth function
|
| +** is a copy of the 3rd argument to this routine. The second argument
|
| +** to the auth function is one of these constants:
|
| +**
|
| +** SQLITE_CREATE_INDEX
|
| +** SQLITE_CREATE_TABLE
|
| +** SQLITE_CREATE_TEMP_INDEX
|
| +** SQLITE_CREATE_TEMP_TABLE
|
| +** SQLITE_CREATE_TEMP_TRIGGER
|
| +** SQLITE_CREATE_TEMP_VIEW
|
| +** SQLITE_CREATE_TRIGGER
|
| +** SQLITE_CREATE_VIEW
|
| +** SQLITE_DELETE
|
| +** SQLITE_DROP_INDEX
|
| +** SQLITE_DROP_TABLE
|
| +** SQLITE_DROP_TEMP_INDEX
|
| +** SQLITE_DROP_TEMP_TABLE
|
| +** SQLITE_DROP_TEMP_TRIGGER
|
| +** SQLITE_DROP_TEMP_VIEW
|
| +** SQLITE_DROP_TRIGGER
|
| +** SQLITE_DROP_VIEW
|
| +** SQLITE_INSERT
|
| +** SQLITE_PRAGMA
|
| +** SQLITE_READ
|
| +** SQLITE_SELECT
|
| +** SQLITE_TRANSACTION
|
| +** SQLITE_UPDATE
|
| +**
|
| +** The third and fourth arguments to the auth function are the name of
|
| +** the table and the column that are being accessed. The auth function
|
| +** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If
|
| +** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY
|
| +** means that the SQL statement will never-run - the sqlite3_exec() call
|
| +** will return with an error. SQLITE_IGNORE means that the SQL statement
|
| +** should run but attempts to read the specified column will return NULL
|
| +** and attempts to write the column will be ignored.
|
| +**
|
| +** Setting the auth function to NULL disables this hook. The default
|
| +** setting of the auth function is NULL.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
|
| + sqlite3 *db,
|
| + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
|
| + void *pArg
|
| +){
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
| +#endif
|
| + sqlite3_mutex_enter(db->mutex);
|
| + db->xAuth = (sqlite3_xauth)xAuth;
|
| + db->pAuthArg = pArg;
|
| + sqlite3ExpirePreparedStatements(db);
|
| + sqlite3_mutex_leave(db->mutex);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Write an error message into pParse->zErrMsg that explains that the
|
| +** user-supplied authorization function returned an illegal value.
|
| +*/
|
| +static void sqliteAuthBadReturnCode(Parse *pParse){
|
| + sqlite3ErrorMsg(pParse, "authorizer malfunction");
|
| + pParse->rc = SQLITE_ERROR;
|
| +}
|
| +
|
| +/*
|
| +** Invoke the authorization callback for permission to read column zCol from
|
| +** table zTab in database zDb. This function assumes that an authorization
|
| +** callback has been registered (i.e. that sqlite3.xAuth is not NULL).
|
| +**
|
| +** If SQLITE_IGNORE is returned and pExpr is not NULL, then pExpr is changed
|
| +** to an SQL NULL expression. Otherwise, if pExpr is NULL, then SQLITE_IGNORE
|
| +** is treated as SQLITE_DENY. In this case an error is left in pParse.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3AuthReadCol(
|
| + Parse *pParse, /* The parser context */
|
| + const char *zTab, /* Table name */
|
| + const char *zCol, /* Column name */
|
| + int iDb /* Index of containing database. */
|
| +){
|
| + sqlite3 *db = pParse->db; /* Database handle */
|
| + char *zDb = db->aDb[iDb].zName; /* Name of attached database */
|
| + int rc; /* Auth callback return code */
|
| +
|
| + rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
|
| +#ifdef SQLITE_USER_AUTHENTICATION
|
| + ,db->auth.zAuthUser
|
| +#endif
|
| + );
|
| + if( rc==SQLITE_DENY ){
|
| + if( db->nDb>2 || iDb!=0 ){
|
| + sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
|
| + }else{
|
| + sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
|
| + }
|
| + pParse->rc = SQLITE_AUTH;
|
| + }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){
|
| + sqliteAuthBadReturnCode(pParse);
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** The pExpr should be a TK_COLUMN expression. The table referred to
|
| +** is in pTabList or else it is the NEW or OLD table of a trigger.
|
| +** Check to see if it is OK to read this particular column.
|
| +**
|
| +** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
|
| +** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
|
| +** then generate an error.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AuthRead(
|
| + Parse *pParse, /* The parser context */
|
| + Expr *pExpr, /* The expression to check authorization on */
|
| + Schema *pSchema, /* The schema of the expression */
|
| + SrcList *pTabList /* All table that pExpr might refer to */
|
| +){
|
| + sqlite3 *db = pParse->db;
|
| + Table *pTab = 0; /* The table being read */
|
| + const char *zCol; /* Name of the column of the table */
|
| + int iSrc; /* Index in pTabList->a[] of table being read */
|
| + int iDb; /* The index of the database the expression refers to */
|
| + int iCol; /* Index of column in table */
|
| +
|
| + if( db->xAuth==0 ) return;
|
| + iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
|
| + if( iDb<0 ){
|
| + /* An attempt to read a column out of a subquery or other
|
| + ** temporary table. */
|
| + return;
|
| + }
|
| +
|
| + assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
|
| + if( pExpr->op==TK_TRIGGER ){
|
| + pTab = pParse->pTriggerTab;
|
| + }else{
|
| + assert( pTabList );
|
| + for(iSrc=0; ALWAYS(iSrc<pTabList->nSrc); iSrc++){
|
| + if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
|
| + pTab = pTabList->a[iSrc].pTab;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + iCol = pExpr->iColumn;
|
| + if( NEVER(pTab==0) ) return;
|
| +
|
| + if( iCol>=0 ){
|
| + assert( iCol<pTab->nCol );
|
| + zCol = pTab->aCol[iCol].zName;
|
| + }else if( pTab->iPKey>=0 ){
|
| + assert( pTab->iPKey<pTab->nCol );
|
| + zCol = pTab->aCol[pTab->iPKey].zName;
|
| + }else{
|
| + zCol = "ROWID";
|
| + }
|
| + assert( iDb>=0 && iDb<db->nDb );
|
| + if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){
|
| + pExpr->op = TK_NULL;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Do an authorization check using the code and arguments given. Return
|
| +** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY
|
| +** is returned, then the error count and error message in pParse are
|
| +** modified appropriately.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3AuthCheck(
|
| + Parse *pParse,
|
| + int code,
|
| + const char *zArg1,
|
| + const char *zArg2,
|
| + const char *zArg3
|
| +){
|
| + sqlite3 *db = pParse->db;
|
| + int rc;
|
| +
|
| + /* Don't do any authorization checks if the database is initialising
|
| + ** or if the parser is being invoked from within sqlite3_declare_vtab.
|
| + */
|
| + if( db->init.busy || IN_DECLARE_VTAB ){
|
| + return SQLITE_OK;
|
| + }
|
| +
|
| + if( db->xAuth==0 ){
|
| + return SQLITE_OK;
|
| + }
|
| + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
|
| +#ifdef SQLITE_USER_AUTHENTICATION
|
| + ,db->auth.zAuthUser
|
| +#endif
|
| + );
|
| + if( rc==SQLITE_DENY ){
|
| + sqlite3ErrorMsg(pParse, "not authorized");
|
| + pParse->rc = SQLITE_AUTH;
|
| + }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
|
| + rc = SQLITE_DENY;
|
| + sqliteAuthBadReturnCode(pParse);
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Push an authorization context. After this routine is called, the
|
| +** zArg3 argument to authorization callbacks will be zContext until
|
| +** popped. Or if pParse==0, this routine is a no-op.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AuthContextPush(
|
| + Parse *pParse,
|
| + AuthContext *pContext,
|
| + const char *zContext
|
| +){
|
| + assert( pParse );
|
| + pContext->pParse = pParse;
|
| + pContext->zAuthContext = pParse->zAuthContext;
|
| + pParse->zAuthContext = zContext;
|
| +}
|
| +
|
| +/*
|
| +** Pop an authorization context that was previously pushed
|
| +** by sqlite3AuthContextPush
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){
|
| + if( pContext->pParse ){
|
| + pContext->pParse->zAuthContext = pContext->zAuthContext;
|
| + pContext->pParse = 0;
|
| + }
|
| +}
|
| +
|
| +#endif /* SQLITE_OMIT_AUTHORIZATION */
|
| +
|
| +/************** End of auth.c ************************************************/
|
| +/************** Begin file build.c *******************************************/
|
| +/*
|
| +** 2001 September 15
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains C code routines that are called by the SQLite parser
|
| +** when syntax rules are reduced. The routines in this file handle the
|
| +** following kinds of SQL syntax:
|
| +**
|
| +** CREATE TABLE
|
| +** DROP TABLE
|
| +** CREATE INDEX
|
| +** DROP INDEX
|
| +** creating ID lists
|
| +** BEGIN TRANSACTION
|
| +** COMMIT
|
| +** ROLLBACK
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +/*
|
| +** This routine is called when a new SQL statement is beginning to
|
| +** be parsed. Initialize the pParse structure as needed.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){
|
| + pParse->explain = (u8)explainFlag;
|
| + pParse->nVar = 0;
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_SHARED_CACHE
|
| +/*
|
| +** The TableLock structure is only used by the sqlite3TableLock() and
|
| +** codeTableLocks() functions.
|
| +*/
|
| +struct TableLock {
|
| + int iDb; /* The database containing the table to be locked */
|
| + int iTab; /* The root page of the table to be locked */
|
| + u8 isWriteLock; /* True for write lock. False for a read lock */
|
| + const char *zName; /* Name of the table */
|
| +};
|
| +
|
| +/*
|
| +** Record the fact that we want to lock a table at run-time.
|
| +**
|
| +** The table to be locked has root page iTab and is found in database iDb.
|
| +** A read or a write lock can be taken depending on isWritelock.
|
| +**
|
| +** This routine just records the fact that the lock is desired. The
|
| +** code to make the lock occur is generated by a later call to
|
| +** codeTableLocks() which occurs during sqlite3FinishCoding().
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3TableLock(
|
| + Parse *pParse, /* Parsing context */
|
| + int iDb, /* Index of the database containing the table to lock */
|
| + int iTab, /* Root page number of the table to be locked */
|
| + u8 isWriteLock, /* True for a write lock */
|
| + const char *zName /* Name of the table to be locked */
|
| +){
|
| + Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + int i;
|
| + int nBytes;
|
| + TableLock *p;
|
| + assert( iDb>=0 );
|
| +
|
| + for(i=0; i<pToplevel->nTableLock; i++){
|
| + p = &pToplevel->aTableLock[i];
|
| + if( p->iDb==iDb && p->iTab==iTab ){
|
| + p->isWriteLock = (p->isWriteLock || isWriteLock);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1);
|
| + pToplevel->aTableLock =
|
| + sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes);
|
| + if( pToplevel->aTableLock ){
|
| + p = &pToplevel->aTableLock[pToplevel->nTableLock++];
|
| + p->iDb = iDb;
|
| + p->iTab = iTab;
|
| + p->isWriteLock = isWriteLock;
|
| + p->zName = zName;
|
| + }else{
|
| + pToplevel->nTableLock = 0;
|
| + pToplevel->db->mallocFailed = 1;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Code an OP_TableLock instruction for each table locked by the
|
| +** statement (configured by calls to sqlite3TableLock()).
|
| +*/
|
| +static void codeTableLocks(Parse *pParse){
|
| + int i;
|
| + Vdbe *pVdbe;
|
| +
|
| + pVdbe = sqlite3GetVdbe(pParse);
|
| + assert( pVdbe!=0 ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */
|
| +
|
| + for(i=0; i<pParse->nTableLock; i++){
|
| + TableLock *p = &pParse->aTableLock[i];
|
| + int p1 = p->iDb;
|
| + sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock,
|
| + p->zName, P4_STATIC);
|
| + }
|
| +}
|
| +#else
|
| + #define codeTableLocks(x)
|
| +#endif
|
| +
|
| +/*
|
| +** Return TRUE if the given yDbMask object is empty - if it contains no
|
| +** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero()
|
| +** macros when SQLITE_MAX_ATTACHED is greater than 30.
|
| +*/
|
| +#if SQLITE_MAX_ATTACHED>30
|
| +SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){
|
| + int i;
|
| + for(i=0; i<sizeof(yDbMask); i++) if( m[i] ) return 0;
|
| + return 1;
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** This routine is called after a single SQL statement has been
|
| +** parsed and a VDBE program to execute that statement has been
|
| +** prepared. This routine puts the finishing touches on the
|
| +** VDBE program and resets the pParse structure for the next
|
| +** parse.
|
| +**
|
| +** Note that if an error occurred, it might be the case that
|
| +** no VDBE code was generated.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
|
| + sqlite3 *db;
|
| + Vdbe *v;
|
| +
|
| + assert( pParse->pToplevel==0 );
|
| + db = pParse->db;
|
| + if( pParse->nested ) return;
|
| + if( db->mallocFailed || pParse->nErr ){
|
| + if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR;
|
| + return;
|
| + }
|
| +
|
| + /* Begin by generating some termination code at the end of the
|
| + ** vdbe program
|
| + */
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( !pParse->isMultiWrite
|
| + || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
|
| + if( v ){
|
| + while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){}
|
| + sqlite3VdbeAddOp0(v, OP_Halt);
|
| +
|
| +#if SQLITE_USER_AUTHENTICATION
|
| + if( pParse->nTableLock>0 && db->init.busy==0 ){
|
| + sqlite3UserAuthInit(db);
|
| + if( db->auth.authLevel<UAUTH_User ){
|
| + pParse->rc = SQLITE_AUTH_USER;
|
| + sqlite3ErrorMsg(pParse, "user not authenticated");
|
| + return;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* The cookie mask contains one bit for each database file open.
|
| + ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
|
| + ** set for each database that is used. Generate code to start a
|
| + ** transaction on each used database and to verify the schema cookie
|
| + ** on each used database.
|
| + */
|
| + if( db->mallocFailed==0
|
| + && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
|
| + ){
|
| + int iDb, i;
|
| + assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
|
| + sqlite3VdbeJumpHere(v, 0);
|
| + for(iDb=0; iDb<db->nDb; iDb++){
|
| + if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
|
| + sqlite3VdbeUsesBtree(v, iDb);
|
| + sqlite3VdbeAddOp4Int(v,
|
| + OP_Transaction, /* Opcode */
|
| + iDb, /* P1 */
|
| + DbMaskTest(pParse->writeMask,iDb), /* P2 */
|
| + pParse->cookieValue[iDb], /* P3 */
|
| + db->aDb[iDb].pSchema->iGeneration /* P4 */
|
| + );
|
| + if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
|
| + VdbeComment((v,
|
| + "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
|
| + }
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + for(i=0; i<pParse->nVtabLock; i++){
|
| + char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
|
| + sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
|
| + }
|
| + pParse->nVtabLock = 0;
|
| +#endif
|
| +
|
| + /* Once all the cookies have been verified and transactions opened,
|
| + ** obtain the required table-locks. This is a no-op unless the
|
| + ** shared-cache feature is enabled.
|
| + */
|
| + codeTableLocks(pParse);
|
| +
|
| + /* Initialize any AUTOINCREMENT data structures required.
|
| + */
|
| + sqlite3AutoincrementBegin(pParse);
|
| +
|
| + /* Code constant expressions that where factored out of inner loops */
|
| + if( pParse->pConstExpr ){
|
| + ExprList *pEL = pParse->pConstExpr;
|
| + pParse->okConstFactor = 0;
|
| + for(i=0; i<pEL->nExpr; i++){
|
| + sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
|
| + }
|
| + }
|
| +
|
| + /* Finally, jump back to the beginning of the executable code. */
|
| + sqlite3VdbeGoto(v, 1);
|
| + }
|
| + }
|
| +
|
| +
|
| + /* Get the VDBE program ready for execution
|
| + */
|
| + if( v && pParse->nErr==0 && !db->mallocFailed ){
|
| + assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
|
| + /* A minimum of one cursor is required if autoincrement is used
|
| + * See ticket [a696379c1f08866] */
|
| + if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
|
| + sqlite3VdbeMakeReady(v, pParse);
|
| + pParse->rc = SQLITE_DONE;
|
| + pParse->colNamesSet = 0;
|
| + }else{
|
| + pParse->rc = SQLITE_ERROR;
|
| + }
|
| + pParse->nTab = 0;
|
| + pParse->nMem = 0;
|
| + pParse->nSet = 0;
|
| + pParse->nVar = 0;
|
| + DbMaskZero(pParse->cookieMask);
|
| +}
|
| +
|
| +/*
|
| +** Run the parser and code generator recursively in order to generate
|
| +** code for the SQL statement given onto the end of the pParse context
|
| +** currently under construction. When the parser is run recursively
|
| +** this way, the final OP_Halt is not appended and other initialization
|
| +** and finalization steps are omitted because those are handling by the
|
| +** outermost parser.
|
| +**
|
| +** Not everything is nestable. This facility is designed to permit
|
| +** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use
|
| +** care if you decide to try to use this routine for some other purposes.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
| + va_list ap;
|
| + char *zSql;
|
| + char *zErrMsg = 0;
|
| + sqlite3 *db = pParse->db;
|
| +# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar))
|
| + char saveBuf[SAVE_SZ];
|
| +
|
| + if( pParse->nErr ) return;
|
| + assert( pParse->nested<10 ); /* Nesting should only be of limited depth */
|
| + va_start(ap, zFormat);
|
| + zSql = sqlite3VMPrintf(db, zFormat, ap);
|
| + va_end(ap);
|
| + if( zSql==0 ){
|
| + return; /* A malloc must have failed */
|
| + }
|
| + pParse->nested++;
|
| + memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
|
| + memset(&pParse->nVar, 0, SAVE_SZ);
|
| + sqlite3RunParser(pParse, zSql, &zErrMsg);
|
| + sqlite3DbFree(db, zErrMsg);
|
| + sqlite3DbFree(db, zSql);
|
| + memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
|
| + pParse->nested--;
|
| +}
|
| +
|
| +#if SQLITE_USER_AUTHENTICATION
|
| +/*
|
| +** Return TRUE if zTable is the name of the system table that stores the
|
| +** list of users and their access credentials.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){
|
| + return sqlite3_stricmp(zTable, "sqlite_user")==0;
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** Locate the in-memory structure that describes a particular database
|
| +** table given the name of that table and (optionally) the name of the
|
| +** database containing the table. Return NULL if not found.
|
| +**
|
| +** If zDatabase is 0, all databases are searched for the table and the
|
| +** first matching table is returned. (No checking for duplicate table
|
| +** names is done.) The search order is TEMP first, then MAIN, then any
|
| +** auxiliary databases added using the ATTACH command.
|
| +**
|
| +** See also sqlite3LocateTable().
|
| +*/
|
| +SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
| + Table *p = 0;
|
| + int i;
|
| +
|
| + /* All mutexes are required for schema access. Make sure we hold them. */
|
| + assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
| +#if SQLITE_USER_AUTHENTICATION
|
| + /* Only the admin user is allowed to know that the sqlite_user table
|
| + ** exists */
|
| + if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
|
| + return 0;
|
| + }
|
| +#endif
|
| + for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
| + int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
| + if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
|
| + assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
| + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
|
| + if( p ) break;
|
| + }
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** Locate the in-memory structure that describes a particular database
|
| +** table given the name of that table and (optionally) the name of the
|
| +** database containing the table. Return NULL if not found. Also leave an
|
| +** error message in pParse->zErrMsg.
|
| +**
|
| +** The difference between this routine and sqlite3FindTable() is that this
|
| +** routine leaves an error message in pParse->zErrMsg where
|
| +** sqlite3FindTable() does not.
|
| +*/
|
| +SQLITE_PRIVATE Table *sqlite3LocateTable(
|
| + Parse *pParse, /* context in which to report errors */
|
| + int isView, /* True if looking for a VIEW rather than a TABLE */
|
| + const char *zName, /* Name of the table we are looking for */
|
| + const char *zDbase /* Name of the database. Might be NULL */
|
| +){
|
| + Table *p;
|
| +
|
| + /* Read the database schema. If an error occurs, leave an error message
|
| + ** and code in pParse and return NULL. */
|
| + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
| + return 0;
|
| + }
|
| +
|
| + p = sqlite3FindTable(pParse->db, zName, zDbase);
|
| + if( p==0 ){
|
| + const char *zMsg = isView ? "no such view" : "no such table";
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
|
| + /* If zName is the not the name of a table in the schema created using
|
| + ** CREATE, then check to see if it is the name of an virtual table that
|
| + ** can be an eponymous virtual table. */
|
| + Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName);
|
| + if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
|
| + return pMod->pEpoTab;
|
| + }
|
| + }
|
| +#endif
|
| + if( zDbase ){
|
| + sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
|
| + }else{
|
| + sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
|
| + }
|
| + pParse->checkSchema = 1;
|
| + }
|
| +
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** Locate the table identified by *p.
|
| +**
|
| +** This is a wrapper around sqlite3LocateTable(). The difference between
|
| +** sqlite3LocateTable() and this function is that this function restricts
|
| +** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be
|
| +** non-NULL if it is part of a view or trigger program definition. See
|
| +** sqlite3FixSrcList() for details.
|
| +*/
|
| +SQLITE_PRIVATE Table *sqlite3LocateTableItem(
|
| + Parse *pParse,
|
| + int isView,
|
| + struct SrcList_item *p
|
| +){
|
| + const char *zDb;
|
| + assert( p->pSchema==0 || p->zDatabase==0 );
|
| + if( p->pSchema ){
|
| + int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
|
| + zDb = pParse->db->aDb[iDb].zName;
|
| + }else{
|
| + zDb = p->zDatabase;
|
| + }
|
| + return sqlite3LocateTable(pParse, isView, p->zName, zDb);
|
| +}
|
| +
|
| +/*
|
| +** Locate the in-memory structure that describes
|
| +** a particular index given the name of that index
|
| +** and the name of the database that contains the index.
|
| +** Return NULL if not found.
|
| +**
|
| +** If zDatabase is 0, all databases are searched for the
|
| +** table and the first matching index is returned. (No checking
|
| +** for duplicate index names is done.) The search order is
|
| +** TEMP first, then MAIN, then any auxiliary databases added
|
| +** using the ATTACH command.
|
| +*/
|
| +SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
| + Index *p = 0;
|
| + int i;
|
| + /* All mutexes are required for schema access. Make sure we hold them. */
|
| + assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
| + for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
| + int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
| + Schema *pSchema = db->aDb[j].pSchema;
|
| + assert( pSchema );
|
| + if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
|
| + assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
| + p = sqlite3HashFind(&pSchema->idxHash, zName);
|
| + if( p ) break;
|
| + }
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** Reclaim the memory used by an index
|
| +*/
|
| +static void freeIndex(sqlite3 *db, Index *p){
|
| +#ifndef SQLITE_OMIT_ANALYZE
|
| + sqlite3DeleteIndexSamples(db, p);
|
| +#endif
|
| + sqlite3ExprDelete(db, p->pPartIdxWhere);
|
| + sqlite3ExprListDelete(db, p->aColExpr);
|
| + sqlite3DbFree(db, p->zColAff);
|
| + if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl);
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + sqlite3_free(p->aiRowEst);
|
| +#endif
|
| + sqlite3DbFree(db, p);
|
| +}
|
| +
|
| +/*
|
| +** For the index called zIdxName which is found in the database iDb,
|
| +** unlike that index from its Table then remove the index from
|
| +** the index hash table and free all memory structures associated
|
| +** with the index.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
| + Index *pIndex;
|
| + Hash *pHash;
|
| +
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + pHash = &db->aDb[iDb].pSchema->idxHash;
|
| + pIndex = sqlite3HashInsert(pHash, zIdxName, 0);
|
| + if( ALWAYS(pIndex) ){
|
| + if( pIndex->pTable->pIndex==pIndex ){
|
| + pIndex->pTable->pIndex = pIndex->pNext;
|
| + }else{
|
| + Index *p;
|
| + /* Justification of ALWAYS(); The index must be on the list of
|
| + ** indices. */
|
| + p = pIndex->pTable->pIndex;
|
| + while( ALWAYS(p) && p->pNext!=pIndex ){ p = p->pNext; }
|
| + if( ALWAYS(p && p->pNext==pIndex) ){
|
| + p->pNext = pIndex->pNext;
|
| + }
|
| + }
|
| + freeIndex(db, pIndex);
|
| + }
|
| + db->flags |= SQLITE_InternChanges;
|
| +}
|
| +
|
| +/*
|
| +** Look through the list of open database files in db->aDb[] and if
|
| +** any have been closed, remove them from the list. Reallocate the
|
| +** db->aDb[] structure to a smaller size, if possible.
|
| +**
|
| +** Entry 0 (the "main" database) and entry 1 (the "temp" database)
|
| +** are never candidates for being collapsed.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
|
| + int i, j;
|
| + for(i=j=2; i<db->nDb; i++){
|
| + struct Db *pDb = &db->aDb[i];
|
| + if( pDb->pBt==0 ){
|
| + sqlite3DbFree(db, pDb->zName);
|
| + pDb->zName = 0;
|
| + continue;
|
| + }
|
| + if( j<i ){
|
| + db->aDb[j] = db->aDb[i];
|
| + }
|
| + j++;
|
| + }
|
| + memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
|
| + db->nDb = j;
|
| + if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
|
| + memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
|
| + sqlite3DbFree(db, db->aDb);
|
| + db->aDb = db->aDbStatic;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Reset the schema for the database at index iDb. Also reset the
|
| +** TEMP schema.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
|
| + Db *pDb;
|
| + assert( iDb<db->nDb );
|
| +
|
| + /* Case 1: Reset the single schema identified by iDb */
|
| + pDb = &db->aDb[iDb];
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + assert( pDb->pSchema!=0 );
|
| + sqlite3SchemaClear(pDb->pSchema);
|
| +
|
| + /* If any database other than TEMP is reset, then also reset TEMP
|
| + ** since TEMP might be holding triggers that reference tables in the
|
| + ** other database.
|
| + */
|
| + if( iDb!=1 ){
|
| + pDb = &db->aDb[1];
|
| + assert( pDb->pSchema!=0 );
|
| + sqlite3SchemaClear(pDb->pSchema);
|
| + }
|
| + return;
|
| +}
|
| +
|
| +/*
|
| +** Erase all schema information from all attached databases (including
|
| +** "main" and "temp") for a single database connection.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
|
| + int i;
|
| + sqlite3BtreeEnterAll(db);
|
| + for(i=0; i<db->nDb; i++){
|
| + Db *pDb = &db->aDb[i];
|
| + if( pDb->pSchema ){
|
| + sqlite3SchemaClear(pDb->pSchema);
|
| + }
|
| + }
|
| + db->flags &= ~SQLITE_InternChanges;
|
| + sqlite3VtabUnlockList(db);
|
| + sqlite3BtreeLeaveAll(db);
|
| + sqlite3CollapseDatabaseArray(db);
|
| +}
|
| +
|
| +/*
|
| +** This routine is called when a commit occurs.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){
|
| + db->flags &= ~SQLITE_InternChanges;
|
| +}
|
| +
|
| +/*
|
| +** Delete memory allocated for the column names of a table or view (the
|
| +** Table.aCol[] array).
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
|
| + int i;
|
| + Column *pCol;
|
| + assert( pTable!=0 );
|
| + if( (pCol = pTable->aCol)!=0 ){
|
| + for(i=0; i<pTable->nCol; i++, pCol++){
|
| + sqlite3DbFree(db, pCol->zName);
|
| + sqlite3ExprDelete(db, pCol->pDflt);
|
| + sqlite3DbFree(db, pCol->zDflt);
|
| + sqlite3DbFree(db, pCol->zType);
|
| + sqlite3DbFree(db, pCol->zColl);
|
| + }
|
| + sqlite3DbFree(db, pTable->aCol);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Remove the memory data structures associated with the given
|
| +** Table. No changes are made to disk by this routine.
|
| +**
|
| +** This routine just deletes the data structure. It does not unlink
|
| +** the table data structure from the hash table. But it does destroy
|
| +** memory structures of the indices and foreign keys associated with
|
| +** the table.
|
| +**
|
| +** The db parameter is optional. It is needed if the Table object
|
| +** contains lookaside memory. (Table objects in the schema do not use
|
| +** lookaside memory, but some ephemeral Table objects do.) Or the
|
| +** db parameter can be used with db->pnBytesFreed to measure the memory
|
| +** used by the Table object.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
| + Index *pIndex, *pNext;
|
| + TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
|
| +
|
| + assert( !pTable || pTable->nRef>0 );
|
| +
|
| + /* Do not delete the table until the reference count reaches zero. */
|
| + if( !pTable ) return;
|
| + if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
|
| +
|
| + /* Record the number of outstanding lookaside allocations in schema Tables
|
| + ** prior to doing any free() operations. Since schema Tables do not use
|
| + ** lookaside, this number should not change. */
|
| + TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
|
| + db->lookaside.nOut : 0 );
|
| +
|
| + /* Delete all indices associated with this table. */
|
| + for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
|
| + pNext = pIndex->pNext;
|
| + assert( pIndex->pSchema==pTable->pSchema );
|
| + if( !db || db->pnBytesFreed==0 ){
|
| + char *zName = pIndex->zName;
|
| + TESTONLY ( Index *pOld = ) sqlite3HashInsert(
|
| + &pIndex->pSchema->idxHash, zName, 0
|
| + );
|
| + assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
| + assert( pOld==pIndex || pOld==0 );
|
| + }
|
| + freeIndex(db, pIndex);
|
| + }
|
| +
|
| + /* Delete any foreign keys attached to this table. */
|
| + sqlite3FkDelete(db, pTable);
|
| +
|
| + /* Delete the Table structure itself.
|
| + */
|
| + sqlite3DeleteColumnNames(db, pTable);
|
| + sqlite3DbFree(db, pTable->zName);
|
| + sqlite3DbFree(db, pTable->zColAff);
|
| + sqlite3SelectDelete(db, pTable->pSelect);
|
| + sqlite3ExprListDelete(db, pTable->pCheck);
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + sqlite3VtabClear(db, pTable);
|
| +#endif
|
| + sqlite3DbFree(db, pTable);
|
| +
|
| + /* Verify that no lookaside memory was used by schema tables */
|
| + assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
|
| +}
|
| +
|
| +/*
|
| +** Unlink the given table from the hash tables and the delete the
|
| +** table structure with all its indices and foreign keys.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
|
| + Table *p;
|
| + Db *pDb;
|
| +
|
| + assert( db!=0 );
|
| + assert( iDb>=0 && iDb<db->nDb );
|
| + assert( zTabName );
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */
|
| + pDb = &db->aDb[iDb];
|
| + p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
|
| + sqlite3DeleteTable(db, p);
|
| + db->flags |= SQLITE_InternChanges;
|
| +}
|
| +
|
| +/*
|
| +** Given a token, return a string that consists of the text of that
|
| +** token. Space to hold the returned string
|
| +** is obtained from sqliteMalloc() and must be freed by the calling
|
| +** function.
|
| +**
|
| +** Any quotation marks (ex: "name", 'name', [name], or `name`) that
|
| +** surround the body of the token are removed.
|
| +**
|
| +** Tokens are often just pointers into the original SQL text and so
|
| +** are not \000 terminated and are not persistent. The returned string
|
| +** is \000 terminated and is persistent.
|
| +*/
|
| +SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
|
| + char *zName;
|
| + if( pName ){
|
| + 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));
|
| + sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
|
| + if( p->nTab==0 ){
|
| + p->nTab = 1;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Parameter zName points to a nul-terminated buffer containing the name
|
| +** of a database ("main", "temp" or the name of an attached db). This
|
| +** function returns the index of the named database in db->aDb[], or
|
| +** -1 if the named db cannot be found.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){
|
| + int i = -1; /* Database number */
|
| + if( zName ){
|
| + Db *pDb;
|
| + int n = sqlite3Strlen30(zName);
|
| + for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
|
| + if( (!OMIT_TEMPDB || i!=1 ) && n==sqlite3Strlen30(pDb->zName) &&
|
| + 0==sqlite3StrICmp(pDb->zName, zName) ){
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + return i;
|
| +}
|
| +
|
| +/*
|
| +** The token *pName contains the name of a database (either "main" or
|
| +** "temp" or the name of an attached db). This routine returns the
|
| +** index of the named database in db->aDb[], or -1 if the named db
|
| +** does not exist.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){
|
| + int i; /* Database number */
|
| + char *zName; /* Name we are searching for */
|
| + zName = sqlite3NameFromToken(db, pName);
|
| + i = sqlite3FindDbName(db, zName);
|
| + sqlite3DbFree(db, zName);
|
| + return i;
|
| +}
|
| +
|
| +/* The table or view or trigger name is passed to this routine via tokens
|
| +** pName1 and pName2. If the table name was fully qualified, for example:
|
| +**
|
| +** CREATE TABLE xxx.yyy (...);
|
| +**
|
| +** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
|
| +** the table name is not fully qualified, i.e.:
|
| +**
|
| +** CREATE TABLE yyy(...);
|
| +**
|
| +** Then pName1 is set to "yyy" and pName2 is "".
|
| +**
|
| +** This routine sets the *ppUnqual pointer to point at the token (pName1 or
|
| +** pName2) that stores the unqualified table name. The index of the
|
| +** database "xxx" is returned.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3TwoPartName(
|
| + Parse *pParse, /* Parsing and code generating context */
|
| + Token *pName1, /* The "xxx" in the name "xxx.yyy" or "xxx" */
|
| + Token *pName2, /* The "yyy" in the name "xxx.yyy" */
|
| + Token **pUnqual /* Write the unqualified object name here */
|
| +){
|
| + int iDb; /* Database holding the object */
|
| + sqlite3 *db = pParse->db;
|
| +
|
| + if( ALWAYS(pName2!=0) && pName2->n>0 ){
|
| + if( db->init.busy ) {
|
| + sqlite3ErrorMsg(pParse, "corrupt database");
|
| + return -1;
|
| + }
|
| + *pUnqual = pName2;
|
| + iDb = sqlite3FindDb(db, pName1);
|
| + if( iDb<0 ){
|
| + sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
|
| + return -1;
|
| + }
|
| + }else{
|
| + assert( db->init.iDb==0 || db->init.busy );
|
| + iDb = db->init.iDb;
|
| + *pUnqual = pName1;
|
| + }
|
| + return iDb;
|
| +}
|
| +
|
| +/*
|
| +** This routine is used to check if the UTF-8 string zName is a legal
|
| +** unqualified name for a new schema object (table, index, view or
|
| +** trigger). All names are legal except those that begin with the string
|
| +** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
|
| +** is reserved for internal use.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){
|
| + if( !pParse->db->init.busy && pParse->nested==0
|
| + && (pParse->db->flags & SQLITE_WriteSchema)==0
|
| + && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
|
| + sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName);
|
| + return SQLITE_ERROR;
|
| + }
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Return the PRIMARY KEY index of a table
|
| +*/
|
| +SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){
|
| + Index *p;
|
| + for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){}
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** Return the column of index pIdx that corresponds to table
|
| +** column iCol. Return -1 if not found.
|
| +*/
|
| +SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
|
| + int i;
|
| + for(i=0; i<pIdx->nColumn; i++){
|
| + if( iCol==pIdx->aiColumn[i] ) return i;
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| +/*
|
| +** Begin constructing a new table representation in memory. This is
|
| +** the first of several action routines that get called in response
|
| +** to a CREATE TABLE statement. In particular, this routine is called
|
| +** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp
|
| +** flag is true if the table should be stored in the auxiliary database
|
| +** file instead of in the main database file. This is normally the case
|
| +** when the "TEMP" or "TEMPORARY" keyword occurs in between
|
| +** CREATE and TABLE.
|
| +**
|
| +** The new table record is initialized and put in pParse->pNewTable.
|
| +** As more of the CREATE TABLE statement is parsed, additional action
|
| +** routines will be called to add more information to this record.
|
| +** At the end of the CREATE TABLE statement, the sqlite3EndTable() routine
|
| +** is called to complete the construction of the new table record.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3StartTable(
|
| + Parse *pParse, /* Parser context */
|
| + Token *pName1, /* First part of the name of the table or view */
|
| + Token *pName2, /* Second part of the name of the table or view */
|
| + int isTemp, /* True if this is a TEMP table */
|
| + int isView, /* True if this is a VIEW */
|
| + int isVirtual, /* True if this is a VIRTUAL table */
|
| + int noErr /* Do nothing if table already exists */
|
| +){
|
| + Table *pTable;
|
| + char *zName = 0; /* The name of the new table */
|
| + sqlite3 *db = pParse->db;
|
| + Vdbe *v;
|
| + int iDb; /* Database number to create the table in */
|
| + Token *pName; /* Unqualified name of the table to create */
|
| +
|
| + /* The table or view name to create is passed to this routine via tokens
|
| + ** pName1 and pName2. If the table name was fully qualified, for example:
|
| + **
|
| + ** CREATE TABLE xxx.yyy (...);
|
| + **
|
| + ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
|
| + ** the table name is not fully qualified, i.e.:
|
| + **
|
| + ** CREATE TABLE yyy(...);
|
| + **
|
| + ** Then pName1 is set to "yyy" and pName2 is "".
|
| + **
|
| + ** The call below sets the pName pointer to point at the token (pName1 or
|
| + ** pName2) that stores the unqualified table name. The variable iDb is
|
| + ** set to the index of the database that the table or view is to be
|
| + ** created in.
|
| + */
|
| + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
| + if( iDb<0 ) return;
|
| + if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
|
| + /* If creating a temp table, the name may not be qualified. Unless
|
| + ** the database name is "temp" anyway. */
|
| + sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
|
| + return;
|
| + }
|
| + if( !OMIT_TEMPDB && isTemp ) iDb = 1;
|
| +
|
| + pParse->sNameToken = *pName;
|
| + zName = sqlite3NameFromToken(db, pName);
|
| + if( zName==0 ) return;
|
| + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
| + goto begin_table_error;
|
| + }
|
| + if( db->init.iDb==1 ) isTemp = 1;
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + assert( (isTemp & 1)==isTemp );
|
| + {
|
| + int code;
|
| + char *zDb = db->aDb[iDb].zName;
|
| + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
|
| + goto begin_table_error;
|
| + }
|
| + if( isView ){
|
| + if( !OMIT_TEMPDB && isTemp ){
|
| + code = SQLITE_CREATE_TEMP_VIEW;
|
| + }else{
|
| + code = SQLITE_CREATE_VIEW;
|
| + }
|
| + }else{
|
| + if( !OMIT_TEMPDB && isTemp ){
|
| + code = SQLITE_CREATE_TEMP_TABLE;
|
| + }else{
|
| + code = SQLITE_CREATE_TABLE;
|
| + }
|
| + }
|
| + if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
|
| + goto begin_table_error;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* Make sure the new table name does not collide with an existing
|
| + ** index or table name in the same database. Issue an error message if
|
| + ** it does. The exception is if the statement being parsed was passed
|
| + ** to an sqlite3_declare_vtab() call. In that case only the column names
|
| + ** and types will be used, so there is no need to test for namespace
|
| + ** collisions.
|
| + */
|
| + if( !IN_DECLARE_VTAB ){
|
| + char *zDb = db->aDb[iDb].zName;
|
| + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
| + goto begin_table_error;
|
| + }
|
| + pTable = sqlite3FindTable(db, zName, zDb);
|
| + if( pTable ){
|
| + if( !noErr ){
|
| + sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
| + }else{
|
| + assert( !db->init.busy || CORRUPT_DB );
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + }
|
| + goto begin_table_error;
|
| + }
|
| + if( sqlite3FindIndex(db, zName, zDb)!=0 ){
|
| + sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
|
| + goto begin_table_error;
|
| + }
|
| + }
|
| +
|
| + pTable = sqlite3DbMallocZero(db, sizeof(Table));
|
| + if( pTable==0 ){
|
| + db->mallocFailed = 1;
|
| + pParse->rc = SQLITE_NOMEM;
|
| + pParse->nErr++;
|
| + goto begin_table_error;
|
| + }
|
| + pTable->zName = zName;
|
| + pTable->iPKey = -1;
|
| + pTable->pSchema = db->aDb[iDb].pSchema;
|
| + pTable->nRef = 1;
|
| + pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
| + assert( pParse->pNewTable==0 );
|
| + pParse->pNewTable = pTable;
|
| +
|
| + /* If this is the magic sqlite_sequence table used by autoincrement,
|
| + ** then record a pointer to this table in the main database structure
|
| + ** so that INSERT can find the table easily.
|
| + */
|
| +#ifndef SQLITE_OMIT_AUTOINCREMENT
|
| + if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + pTable->pSchema->pSeqTab = pTable;
|
| + }
|
| +#endif
|
| +
|
| + /* Begin generating the code that will insert the table record into
|
| + ** the SQLITE_MASTER table. Note in particular that we must go ahead
|
| + ** and allocate the record number for the table entry now. Before any
|
| + ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause
|
| + ** indices to be created and the table record must come before the
|
| + ** indices. Hence, the record number for the table must be allocated
|
| + ** now.
|
| + */
|
| + if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
|
| + int addr1;
|
| + int fileFormat;
|
| + int reg1, reg2, reg3;
|
| + /* nullRow[] is an OP_Record encoding of a row containing 5 NULLs */
|
| + static const char nullRow[] = { 6, 0, 0, 0, 0, 0 };
|
| + sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| +
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( isVirtual ){
|
| + sqlite3VdbeAddOp0(v, OP_VBegin);
|
| + }
|
| +#endif
|
| +
|
| + /* If the file format and encoding in the database have not been set,
|
| + ** set them now.
|
| + */
|
| + reg1 = pParse->regRowid = ++pParse->nMem;
|
| + reg2 = pParse->regRoot = ++pParse->nMem;
|
| + reg3 = ++pParse->nMem;
|
| + sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
|
| + sqlite3VdbeUsesBtree(v, iDb);
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
|
| + fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
|
| + 1 : SQLITE_MAX_FILE_FORMAT;
|
| + sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
|
| + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
|
| + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| +
|
| + /* This just creates a place-holder record in the sqlite_master table.
|
| + ** The record created does not contain anything yet. It will be replaced
|
| + ** by the real entry in code generated at sqlite3EndTable().
|
| + **
|
| + ** The rowid for the new entry is left in register pParse->regRowid.
|
| + ** The root page number of the new table is left in reg pParse->regRoot.
|
| + ** The rowid and root page number values are needed by the code that
|
| + ** sqlite3EndTable will generate.
|
| + */
|
| +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
| + if( isView || isVirtual ){
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, reg2);
|
| + }else
|
| +#endif
|
| + {
|
| + pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
|
| + }
|
| + sqlite3OpenMasterTable(pParse, iDb);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
|
| + sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| + sqlite3VdbeAddOp0(v, OP_Close);
|
| + }
|
| +
|
| + /* Normal (non-error) return. */
|
| + return;
|
| +
|
| + /* If an error occurs, we jump here */
|
| +begin_table_error:
|
| + sqlite3DbFree(db, zName);
|
| + return;
|
| +}
|
| +
|
| +/* Set properties of a table column based on the (magical)
|
| +** name of the column.
|
| +*/
|
| +#if SQLITE_ENABLE_HIDDEN_COLUMNS
|
| +SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
|
| + if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){
|
| + pCol->colFlags |= COLFLAG_HIDDEN;
|
| + }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){
|
| + pTab->tabFlags |= TF_OOOHidden;
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** Add a new column to the table currently being constructed.
|
| +**
|
| +** The parser calls this routine once for each column declaration
|
| +** in a CREATE TABLE statement. sqlite3StartTable() gets called
|
| +** first to get things going. Then this routine is called for each
|
| +** column.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
|
| + Table *p;
|
| + int i;
|
| + char *z;
|
| + Column *pCol;
|
| + sqlite3 *db = pParse->db;
|
| + if( (p = pParse->pNewTable)==0 ) return;
|
| +#if SQLITE_MAX_COLUMN
|
| + if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
| + sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
|
| + return;
|
| + }
|
| +#endif
|
| + z = sqlite3NameFromToken(db, pName);
|
| + if( z==0 ) return;
|
| + for(i=0; i<p->nCol; i++){
|
| + if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
|
| + sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
|
| + sqlite3DbFree(db, z);
|
| + return;
|
| + }
|
| + }
|
| + if( (p->nCol & 0x7)==0 ){
|
| + Column *aNew;
|
| + aNew = sqlite3DbRealloc(db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0]));
|
| + if( aNew==0 ){
|
| + sqlite3DbFree(db, z);
|
| + return;
|
| + }
|
| + p->aCol = aNew;
|
| + }
|
| + pCol = &p->aCol[p->nCol];
|
| + memset(pCol, 0, sizeof(p->aCol[0]));
|
| + pCol->zName = z;
|
| + sqlite3ColumnPropertiesFromName(p, pCol);
|
| +
|
| + /* If there is no type specified, columns have the default affinity
|
| + ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will
|
| + ** be called next to set pCol->affinity correctly.
|
| + */
|
| + pCol->affinity = SQLITE_AFF_BLOB;
|
| + pCol->szEst = 1;
|
| + p->nCol++;
|
| +}
|
| +
|
| +/*
|
| +** This routine is called by the parser while in the middle of
|
| +** parsing a CREATE TABLE statement. A "NOT NULL" constraint has
|
| +** been seen on a column. This routine sets the notNull flag on
|
| +** the column currently under construction.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){
|
| + Table *p;
|
| + p = pParse->pNewTable;
|
| + if( p==0 || NEVER(p->nCol<1) ) return;
|
| + p->aCol[p->nCol-1].notNull = (u8)onError;
|
| +}
|
| +
|
| +/*
|
| +** Scan the column type name zType (length nType) and return the
|
| +** associated affinity type.
|
| +**
|
| +** This routine does a case-independent search of zType for the
|
| +** substrings in the following table. If one of the substrings is
|
| +** found, the corresponding affinity is returned. If zType contains
|
| +** more than one of the substrings, entries toward the top of
|
| +** the table take priority. For example, if zType is 'BLOBINT',
|
| +** SQLITE_AFF_INTEGER is returned.
|
| +**
|
| +** Substring | Affinity
|
| +** --------------------------------
|
| +** 'INT' | SQLITE_AFF_INTEGER
|
| +** 'CHAR' | SQLITE_AFF_TEXT
|
| +** 'CLOB' | SQLITE_AFF_TEXT
|
| +** 'TEXT' | SQLITE_AFF_TEXT
|
| +** 'BLOB' | SQLITE_AFF_BLOB
|
| +** 'REAL' | SQLITE_AFF_REAL
|
| +** 'FLOA' | SQLITE_AFF_REAL
|
| +** 'DOUB' | SQLITE_AFF_REAL
|
| +**
|
| +** If none of the substrings in the above table are found,
|
| +** SQLITE_AFF_NUMERIC is returned.
|
| +*/
|
| +SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
|
| + u32 h = 0;
|
| + char aff = SQLITE_AFF_NUMERIC;
|
| + const char *zChar = 0;
|
| +
|
| + if( zIn==0 ) return aff;
|
| + while( zIn[0] ){
|
| + h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
|
| + zIn++;
|
| + if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
|
| + aff = SQLITE_AFF_TEXT;
|
| + zChar = zIn;
|
| + }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */
|
| + aff = SQLITE_AFF_TEXT;
|
| + }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
|
| + aff = SQLITE_AFF_TEXT;
|
| + }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
|
| + && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
|
| + aff = SQLITE_AFF_BLOB;
|
| + if( zIn[0]=='(' ) zChar = zIn;
|
| +#ifndef SQLITE_OMIT_FLOATING_POINT
|
| + }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
|
| + && aff==SQLITE_AFF_NUMERIC ){
|
| + aff = SQLITE_AFF_REAL;
|
| + }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */
|
| + && aff==SQLITE_AFF_NUMERIC ){
|
| + aff = SQLITE_AFF_REAL;
|
| + }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */
|
| + && aff==SQLITE_AFF_NUMERIC ){
|
| + aff = SQLITE_AFF_REAL;
|
| +#endif
|
| + }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */
|
| + aff = SQLITE_AFF_INTEGER;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + /* If pszEst is not NULL, store an estimate of the field size. The
|
| + ** estimate is scaled so that the size of an integer is 1. */
|
| + if( pszEst ){
|
| + *pszEst = 1; /* default size is approx 4 bytes */
|
| + if( aff<SQLITE_AFF_NUMERIC ){
|
| + if( zChar ){
|
| + while( zChar[0] ){
|
| + if( sqlite3Isdigit(zChar[0]) ){
|
| + int v = 0;
|
| + sqlite3GetInt32(zChar, &v);
|
| + v = v/4 + 1;
|
| + if( v>255 ) v = 255;
|
| + *pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */
|
| + break;
|
| + }
|
| + zChar++;
|
| + }
|
| + }else{
|
| + *pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/
|
| + }
|
| + }
|
| + }
|
| + return aff;
|
| +}
|
| +
|
| +/*
|
| +** This routine is called by the parser while in the middle of
|
| +** parsing a CREATE TABLE statement. The pFirst token is the first
|
| +** token in the sequence of tokens that describe the type of the
|
| +** column currently under construction. pLast is the last token
|
| +** in the sequence. Use this information to construct a string
|
| +** that contains the typename of the column and store that string
|
| +** in zType.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){
|
| + Table *p;
|
| + Column *pCol;
|
| +
|
| + p = pParse->pNewTable;
|
| + if( p==0 || NEVER(p->nCol<1) ) return;
|
| + pCol = &p->aCol[p->nCol-1];
|
| + assert( pCol->zType==0 || CORRUPT_DB );
|
| + sqlite3DbFree(pParse->db, pCol->zType);
|
| + pCol->zType = sqlite3NameFromToken(pParse->db, pType);
|
| + pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
|
| +}
|
| +
|
| +/*
|
| +** The expression is the default value for the most recently added column
|
| +** of the table currently under construction.
|
| +**
|
| +** Default value expressions must be constant. Raise an exception if this
|
| +** is not the case.
|
| +**
|
| +** This routine is called by the parser while in the middle of
|
| +** parsing a CREATE TABLE statement.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
|
| + Table *p;
|
| + Column *pCol;
|
| + sqlite3 *db = pParse->db;
|
| + p = pParse->pNewTable;
|
| + if( p!=0 ){
|
| + pCol = &(p->aCol[p->nCol-1]);
|
| + if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){
|
| + sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
|
| + pCol->zName);
|
| + }else{
|
| + /* A copy of pExpr is used instead of the original, as pExpr contains
|
| + ** tokens that point to volatile memory. The 'span' of the expression
|
| + ** is required by pragma table_info.
|
| + */
|
| + sqlite3ExprDelete(db, pCol->pDflt);
|
| + pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE);
|
| + sqlite3DbFree(db, pCol->zDflt);
|
| + pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
|
| + (int)(pSpan->zEnd - pSpan->zStart));
|
| + }
|
| + }
|
| + sqlite3ExprDelete(db, pSpan->pExpr);
|
| +}
|
| +
|
| +/*
|
| +** Backwards Compatibility Hack:
|
| +**
|
| +** Historical versions of SQLite accepted strings as column names in
|
| +** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example:
|
| +**
|
| +** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim)
|
| +** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC);
|
| +**
|
| +** This is goofy. But to preserve backwards compatibility we continue to
|
| +** accept it. This routine does the necessary conversion. It converts
|
| +** the expression given in its argument from a TK_STRING into a TK_ID
|
| +** if the expression is just a TK_STRING with an optional COLLATE clause.
|
| +** If the epxression is anything other than TK_STRING, the expression is
|
| +** unchanged.
|
| +*/
|
| +static void sqlite3StringToId(Expr *p){
|
| + if( p->op==TK_STRING ){
|
| + p->op = TK_ID;
|
| + }else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){
|
| + p->pLeft->op = TK_ID;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Designate the PRIMARY KEY for the table. pList is a list of names
|
| +** of columns that form the primary key. If pList is NULL, then the
|
| +** most recently added column of the table is the primary key.
|
| +**
|
| +** A table can have at most one primary key. If the table already has
|
| +** a primary key (and this is the second primary key) then create an
|
| +** error.
|
| +**
|
| +** If the PRIMARY KEY is on a single column whose datatype is INTEGER,
|
| +** then we will try to use that column as the rowid. Set the Table.iPKey
|
| +** field of the table under construction to be the index of the
|
| +** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is
|
| +** no INTEGER PRIMARY KEY.
|
| +**
|
| +** If the key is not an INTEGER PRIMARY KEY, then create a unique
|
| +** index for the key. No index is created for INTEGER PRIMARY KEYs.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AddPrimaryKey(
|
| + Parse *pParse, /* Parsing context */
|
| + ExprList *pList, /* List of field names to be indexed */
|
| + int onError, /* What to do with a uniqueness conflict */
|
| + int autoInc, /* True if the AUTOINCREMENT keyword is present */
|
| + int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
|
| +){
|
| + Table *pTab = pParse->pNewTable;
|
| + char *zType = 0;
|
| + int iCol = -1, i;
|
| + int nTerm;
|
| + if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
|
| + if( pTab->tabFlags & TF_HasPrimaryKey ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "table \"%s\" has more than one primary key", pTab->zName);
|
| + goto primary_key_exit;
|
| + }
|
| + pTab->tabFlags |= TF_HasPrimaryKey;
|
| + if( pList==0 ){
|
| + iCol = pTab->nCol - 1;
|
| + pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
|
| + zType = pTab->aCol[iCol].zType;
|
| + nTerm = 1;
|
| + }else{
|
| + nTerm = pList->nExpr;
|
| + for(i=0; i<nTerm; i++){
|
| + Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr);
|
| + assert( pCExpr!=0 );
|
| + sqlite3StringToId(pCExpr);
|
| + if( pCExpr->op==TK_ID ){
|
| + const char *zCName = pCExpr->u.zToken;
|
| + for(iCol=0; iCol<pTab->nCol; iCol++){
|
| + if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
|
| + pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
|
| + zType = pTab->aCol[iCol].zType;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| + if( nTerm==1
|
| + && zType && sqlite3StrICmp(zType, "INTEGER")==0
|
| + && sortOrder!=SQLITE_SO_DESC
|
| + ){
|
| + pTab->iPKey = iCol;
|
| + pTab->keyConf = (u8)onError;
|
| + assert( autoInc==0 || autoInc==1 );
|
| + pTab->tabFlags |= autoInc*TF_Autoincrement;
|
| + if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder;
|
| + }else if( autoInc ){
|
| +#ifndef SQLITE_OMIT_AUTOINCREMENT
|
| + sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
|
| + "INTEGER PRIMARY KEY");
|
| +#endif
|
| + }else{
|
| + Index *p;
|
| + p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
|
| + 0, sortOrder, 0);
|
| + if( p ){
|
| + p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
|
| + }
|
| + pList = 0;
|
| + }
|
| +
|
| +primary_key_exit:
|
| + sqlite3ExprListDelete(pParse->db, pList);
|
| + return;
|
| +}
|
| +
|
| +/*
|
| +** Add a new CHECK constraint to the table currently under construction.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AddCheckConstraint(
|
| + Parse *pParse, /* Parsing context */
|
| + Expr *pCheckExpr /* The check expression */
|
| +){
|
| +#ifndef SQLITE_OMIT_CHECK
|
| + Table *pTab = pParse->pNewTable;
|
| + sqlite3 *db = pParse->db;
|
| + if( pTab && !IN_DECLARE_VTAB
|
| + && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt)
|
| + ){
|
| + pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
|
| + if( pParse->constraintName.n ){
|
| + sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
|
| + }
|
| + }else
|
| +#endif
|
| + {
|
| + sqlite3ExprDelete(pParse->db, pCheckExpr);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Set the collation function of the most recently parsed table column
|
| +** to the CollSeq given.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
| + Table *p;
|
| + int i;
|
| + char *zColl; /* Dequoted name of collation sequence */
|
| + sqlite3 *db;
|
| +
|
| + if( (p = pParse->pNewTable)==0 ) return;
|
| + i = p->nCol-1;
|
| + db = pParse->db;
|
| + zColl = sqlite3NameFromToken(db, pToken);
|
| + if( !zColl ) return;
|
| +
|
| + if( sqlite3LocateCollSeq(pParse, zColl) ){
|
| + Index *pIdx;
|
| + sqlite3DbFree(db, p->aCol[i].zColl);
|
| + p->aCol[i].zColl = zColl;
|
| +
|
| + /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
|
| + ** then an index may have been created on this column before the
|
| + ** collation type was added. Correct this if it is the case.
|
| + */
|
| + for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + assert( pIdx->nKeyCol==1 );
|
| + if( pIdx->aiColumn[0]==i ){
|
| + pIdx->azColl[0] = p->aCol[i].zColl;
|
| + }
|
| + }
|
| + }else{
|
| + sqlite3DbFree(db, zColl);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This function returns the collation sequence for database native text
|
| +** encoding identified by the string zName, length nName.
|
| +**
|
| +** If the requested collation sequence is not available, or not available
|
| +** in the database native encoding, the collation factory is invoked to
|
| +** request it. If the collation factory does not supply such a sequence,
|
| +** and the sequence is available in another text encoding, then that is
|
| +** returned instead.
|
| +**
|
| +** If no versions of the requested collations sequence are available, or
|
| +** another error occurs, NULL is returned and an error message written into
|
| +** pParse.
|
| +**
|
| +** This routine is a wrapper around sqlite3FindCollSeq(). This routine
|
| +** invokes the collation factory if the named collation cannot be found
|
| +** and generates an error message.
|
| +**
|
| +** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq()
|
| +*/
|
| +SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
|
| + sqlite3 *db = pParse->db;
|
| + u8 enc = ENC(db);
|
| + u8 initbusy = db->init.busy;
|
| + CollSeq *pColl;
|
| +
|
| + pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
|
| + if( !initbusy && (!pColl || !pColl->xCmp) ){
|
| + pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
|
| + }
|
| +
|
| + return pColl;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Generate code that will increment the schema cookie.
|
| +**
|
| +** The schema cookie is used to determine when the schema for the
|
| +** database changes. After each schema change, the cookie value
|
| +** changes. When a process first reads the schema it records the
|
| +** cookie. Thereafter, whenever it goes to access the database,
|
| +** it checks the cookie to make sure the schema has not changed
|
| +** since it was last read.
|
| +**
|
| +** This plan is not completely bullet-proof. It is possible for
|
| +** the schema to change multiple times and for the cookie to be
|
| +** set back to prior value. But schema changes are infrequent
|
| +** and the probability of hitting the same cookie value is only
|
| +** 1 chance in 2^32. So we're safe enough.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){
|
| + int r1 = sqlite3GetTempReg(pParse);
|
| + sqlite3 *db = pParse->db;
|
| + Vdbe *v = pParse->pVdbe;
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1);
|
| + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| +}
|
| +
|
| +/*
|
| +** Measure the number of characters needed to output the given
|
| +** identifier. The number returned includes any quotes used
|
| +** but does not include the null terminator.
|
| +**
|
| +** The estimate is conservative. It might be larger that what is
|
| +** really needed.
|
| +*/
|
| +static int identLength(const char *z){
|
| + int n;
|
| + for(n=0; *z; n++, z++){
|
| + if( *z=='"' ){ n++; }
|
| + }
|
| + return n + 2;
|
| +}
|
| +
|
| +/*
|
| +** The first parameter is a pointer to an output buffer. The second
|
| +** parameter is a pointer to an integer that contains the offset at
|
| +** which to write into the output buffer. This function copies the
|
| +** nul-terminated string pointed to by the third parameter, zSignedIdent,
|
| +** to the specified offset in the buffer and updates *pIdx to refer
|
| +** to the first byte after the last byte written before returning.
|
| +**
|
| +** If the string zSignedIdent consists entirely of alpha-numeric
|
| +** characters, does not begin with a digit and is not an SQL keyword,
|
| +** then it is copied to the output buffer exactly as it is. Otherwise,
|
| +** it is quoted using double-quotes.
|
| +*/
|
| +static void identPut(char *z, int *pIdx, char *zSignedIdent){
|
| + unsigned char *zIdent = (unsigned char*)zSignedIdent;
|
| + int i, j, needQuote;
|
| + i = *pIdx;
|
| +
|
| + for(j=0; zIdent[j]; j++){
|
| + if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
|
| + }
|
| + needQuote = sqlite3Isdigit(zIdent[0])
|
| + || sqlite3KeywordCode(zIdent, j)!=TK_ID
|
| + || zIdent[j]!=0
|
| + || j==0;
|
| +
|
| + if( needQuote ) z[i++] = '"';
|
| + for(j=0; zIdent[j]; j++){
|
| + z[i++] = zIdent[j];
|
| + if( zIdent[j]=='"' ) z[i++] = '"';
|
| + }
|
| + if( needQuote ) z[i++] = '"';
|
| + z[i] = 0;
|
| + *pIdx = i;
|
| +}
|
| +
|
| +/*
|
| +** Generate a CREATE TABLE statement appropriate for the given
|
| +** table. Memory to hold the text of the statement is obtained
|
| +** from sqliteMalloc() and must be freed by the calling function.
|
| +*/
|
| +static char *createTableStmt(sqlite3 *db, Table *p){
|
| + int i, k, n;
|
| + char *zStmt;
|
| + char *zSep, *zSep2, *zEnd;
|
| + Column *pCol;
|
| + n = 0;
|
| + for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){
|
| + n += identLength(pCol->zName) + 5;
|
| + }
|
| + n += identLength(p->zName);
|
| + if( n<50 ){
|
| + zSep = "";
|
| + zSep2 = ",";
|
| + zEnd = ")";
|
| + }else{
|
| + zSep = "\n ";
|
| + zSep2 = ",\n ";
|
| + zEnd = "\n)";
|
| + }
|
| + n += 35 + 6*p->nCol;
|
| + zStmt = sqlite3DbMallocRaw(0, n);
|
| + if( zStmt==0 ){
|
| + db->mallocFailed = 1;
|
| + return 0;
|
| + }
|
| + sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
|
| + k = sqlite3Strlen30(zStmt);
|
| + identPut(zStmt, &k, p->zName);
|
| + zStmt[k++] = '(';
|
| + for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
|
| + static const char * const azType[] = {
|
| + /* SQLITE_AFF_BLOB */ "",
|
| + /* SQLITE_AFF_TEXT */ " TEXT",
|
| + /* SQLITE_AFF_NUMERIC */ " NUM",
|
| + /* SQLITE_AFF_INTEGER */ " INT",
|
| + /* SQLITE_AFF_REAL */ " REAL"
|
| + };
|
| + int len;
|
| + const char *zType;
|
| +
|
| + sqlite3_snprintf(n-k, &zStmt[k], zSep);
|
| + k += sqlite3Strlen30(&zStmt[k]);
|
| + zSep = zSep2;
|
| + identPut(zStmt, &k, pCol->zName);
|
| + assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 );
|
| + assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) );
|
| + testcase( pCol->affinity==SQLITE_AFF_BLOB );
|
| + testcase( pCol->affinity==SQLITE_AFF_TEXT );
|
| + testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
|
| + testcase( pCol->affinity==SQLITE_AFF_INTEGER );
|
| + testcase( pCol->affinity==SQLITE_AFF_REAL );
|
| +
|
| + zType = azType[pCol->affinity - SQLITE_AFF_BLOB];
|
| + len = sqlite3Strlen30(zType);
|
| + assert( pCol->affinity==SQLITE_AFF_BLOB
|
| + || pCol->affinity==sqlite3AffinityType(zType, 0) );
|
| + memcpy(&zStmt[k], zType, len);
|
| + k += len;
|
| + assert( k<=n );
|
| + }
|
| + sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
|
| + return zStmt;
|
| +}
|
| +
|
| +/*
|
| +** Resize an Index object to hold N columns total. Return SQLITE_OK
|
| +** on success and SQLITE_NOMEM on an OOM error.
|
| +*/
|
| +static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
|
| + char *zExtra;
|
| + int nByte;
|
| + if( pIdx->nColumn>=N ) return SQLITE_OK;
|
| + assert( pIdx->isResized==0 );
|
| + nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
|
| + zExtra = sqlite3DbMallocZero(db, nByte);
|
| + if( zExtra==0 ) return SQLITE_NOMEM;
|
| + memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
|
| + pIdx->azColl = (const char**)zExtra;
|
| + zExtra += sizeof(char*)*N;
|
| + memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
|
| + pIdx->aiColumn = (i16*)zExtra;
|
| + zExtra += sizeof(i16)*N;
|
| + memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn);
|
| + pIdx->aSortOrder = (u8*)zExtra;
|
| + pIdx->nColumn = N;
|
| + pIdx->isResized = 1;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Estimate the total row width for a table.
|
| +*/
|
| +static void estimateTableWidth(Table *pTab){
|
| + unsigned wTable = 0;
|
| + const Column *pTabCol;
|
| + int i;
|
| + for(i=pTab->nCol, pTabCol=pTab->aCol; i>0; i--, pTabCol++){
|
| + wTable += pTabCol->szEst;
|
| + }
|
| + if( pTab->iPKey<0 ) wTable++;
|
| + pTab->szTabRow = sqlite3LogEst(wTable*4);
|
| +}
|
| +
|
| +/*
|
| +** Estimate the average size of a row for an index.
|
| +*/
|
| +static void estimateIndexWidth(Index *pIdx){
|
| + unsigned wIndex = 0;
|
| + int i;
|
| + const Column *aCol = pIdx->pTable->aCol;
|
| + for(i=0; i<pIdx->nColumn; i++){
|
| + i16 x = pIdx->aiColumn[i];
|
| + assert( x<pIdx->pTable->nCol );
|
| + wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst;
|
| + }
|
| + pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
|
| +}
|
| +
|
| +/* Return true if value x is found any of the first nCol entries of aiCol[]
|
| +*/
|
| +static int hasColumn(const i16 *aiCol, int nCol, int x){
|
| + while( nCol-- > 0 ) if( x==*(aiCol++) ) return 1;
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** This routine runs at the end of parsing a CREATE TABLE statement that
|
| +** has a WITHOUT ROWID clause. The job of this routine is to convert both
|
| +** internal schema data structures and the generated VDBE code so that they
|
| +** are appropriate for a WITHOUT ROWID table instead of a rowid table.
|
| +** Changes include:
|
| +**
|
| +** (1) Convert the OP_CreateTable into an OP_CreateIndex. There is
|
| +** no rowid btree for a WITHOUT ROWID. Instead, the canonical
|
| +** data storage is a covering index btree.
|
| +** (2) Bypass the creation of the sqlite_master table entry
|
| +** for the PRIMARY KEY as the primary key index is now
|
| +** identified by the sqlite_master table entry of the table itself.
|
| +** (3) Set the Index.tnum of the PRIMARY KEY Index object in the
|
| +** schema to the rootpage from the main table.
|
| +** (4) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
|
| +** (5) Add all table columns to the PRIMARY KEY Index object
|
| +** so that the PRIMARY KEY is a covering index. The surplus
|
| +** columns are part of KeyInfo.nXField and are not used for
|
| +** sorting or lookup or uniqueness checks.
|
| +** (6) Replace the rowid tail on all automatically generated UNIQUE
|
| +** indices with the PRIMARY KEY columns.
|
| +*/
|
| +static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
| + Index *pIdx;
|
| + Index *pPk;
|
| + int nPk;
|
| + int i, j;
|
| + sqlite3 *db = pParse->db;
|
| + Vdbe *v = pParse->pVdbe;
|
| +
|
| + /* Convert the OP_CreateTable opcode that would normally create the
|
| + ** root-page for the table into an OP_CreateIndex opcode. The index
|
| + ** created will become the PRIMARY KEY index.
|
| + */
|
| + if( pParse->addrCrTab ){
|
| + assert( v );
|
| + sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex);
|
| + }
|
| +
|
| + /* Locate the PRIMARY KEY index. Or, if this table was originally
|
| + ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index.
|
| + */
|
| + if( pTab->iPKey>=0 ){
|
| + ExprList *pList;
|
| + Token ipkToken;
|
| + ipkToken.z = pTab->aCol[pTab->iPKey].zName;
|
| + ipkToken.n = sqlite3Strlen30(ipkToken.z);
|
| + pList = sqlite3ExprListAppend(pParse, 0,
|
| + sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0));
|
| + if( pList==0 ) return;
|
| + pList->a[0].sortOrder = pParse->iPkSortOrder;
|
| + assert( pParse->pNewTable==pTab );
|
| + pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
|
| + if( pPk==0 ) return;
|
| + pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
|
| + pTab->iPKey = -1;
|
| + }else{
|
| + pPk = sqlite3PrimaryKeyIndex(pTab);
|
| +
|
| + /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
|
| + ** table entry. This is only required if currently generating VDBE
|
| + ** code for a CREATE TABLE (not when parsing one as part of reading
|
| + ** a database schema). */
|
| + if( v ){
|
| + assert( db->init.busy==0 );
|
| + sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
|
| + }
|
| +
|
| + /*
|
| + ** Remove all redundant columns from the PRIMARY KEY. For example, change
|
| + ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
|
| + ** code assumes the PRIMARY KEY contains no repeated columns.
|
| + */
|
| + for(i=j=1; i<pPk->nKeyCol; i++){
|
| + if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){
|
| + pPk->nColumn--;
|
| + }else{
|
| + pPk->aiColumn[j++] = pPk->aiColumn[i];
|
| + }
|
| + }
|
| + pPk->nKeyCol = j;
|
| + }
|
| + pPk->isCovering = 1;
|
| + assert( pPk!=0 );
|
| + nPk = pPk->nKeyCol;
|
| +
|
| + /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except,
|
| + ** do not enforce this for imposter tables.) */
|
| + if( !db->init.imposterTable ){
|
| + for(i=0; i<nPk; i++){
|
| + pTab->aCol[pPk->aiColumn[i]].notNull = OE_Abort;
|
| + }
|
| + pPk->uniqNotNull = 1;
|
| + }
|
| +
|
| + /* The root page of the PRIMARY KEY is the table root page */
|
| + pPk->tnum = pTab->tnum;
|
| +
|
| + /* Update the in-memory representation of all UNIQUE indices by converting
|
| + ** the final rowid column into one or more columns of the PRIMARY KEY.
|
| + */
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + int n;
|
| + if( IsPrimaryKeyIndex(pIdx) ) continue;
|
| + for(i=n=0; i<nPk; i++){
|
| + if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++;
|
| + }
|
| + if( n==0 ){
|
| + /* This index is a superset of the primary key */
|
| + pIdx->nColumn = pIdx->nKeyCol;
|
| + continue;
|
| + }
|
| + if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return;
|
| + for(i=0, j=pIdx->nKeyCol; i<nPk; i++){
|
| + if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ){
|
| + pIdx->aiColumn[j] = pPk->aiColumn[i];
|
| + pIdx->azColl[j] = pPk->azColl[i];
|
| + j++;
|
| + }
|
| + }
|
| + assert( pIdx->nColumn>=pIdx->nKeyCol+n );
|
| + assert( pIdx->nColumn>=j );
|
| + }
|
| +
|
| + /* Add all table columns to the PRIMARY KEY index
|
| + */
|
| + if( nPk<pTab->nCol ){
|
| + if( resizeIndexObject(db, pPk, pTab->nCol) ) return;
|
| + for(i=0, j=nPk; i<pTab->nCol; i++){
|
| + if( !hasColumn(pPk->aiColumn, j, i) ){
|
| + assert( j<pPk->nColumn );
|
| + pPk->aiColumn[j] = i;
|
| + pPk->azColl[j] = sqlite3StrBINARY;
|
| + j++;
|
| + }
|
| + }
|
| + assert( pPk->nColumn==j );
|
| + assert( pTab->nCol==j );
|
| + }else{
|
| + pPk->nColumn = pTab->nCol;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This routine is called to report the final ")" that terminates
|
| +** a CREATE TABLE statement.
|
| +**
|
| +** The table structure that other action routines have been building
|
| +** is added to the internal hash tables, assuming no errors have
|
| +** occurred.
|
| +**
|
| +** An entry for the table is made in the master table on disk, unless
|
| +** this is a temporary table or db->init.busy==1. When db->init.busy==1
|
| +** it means we are reading the sqlite_master table because we just
|
| +** connected to the database or because the sqlite_master table has
|
| +** recently changed, so the entry for this table already exists in
|
| +** the sqlite_master table. We do not want to create it again.
|
| +**
|
| +** If the pSelect argument is not NULL, it means that this routine
|
| +** was called to create a table generated from a
|
| +** "CREATE TABLE ... AS SELECT ..." statement. The column names of
|
| +** the new table will match the result set of the SELECT.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3EndTable(
|
| + Parse *pParse, /* Parse context */
|
| + Token *pCons, /* The ',' token after the last column defn. */
|
| + Token *pEnd, /* The ')' before options in the CREATE TABLE */
|
| + u8 tabOpts, /* Extra table options. Usually 0. */
|
| + Select *pSelect /* Select from a "CREATE ... AS SELECT" */
|
| +){
|
| + Table *p; /* The new table */
|
| + sqlite3 *db = pParse->db; /* The database connection */
|
| + int iDb; /* Database in which the table lives */
|
| + Index *pIdx; /* An implied index of the table */
|
| +
|
| + if( pEnd==0 && pSelect==0 ){
|
| + return;
|
| + }
|
| + assert( !db->mallocFailed );
|
| + p = pParse->pNewTable;
|
| + if( p==0 ) return;
|
| +
|
| + assert( !db->init.busy || !pSelect );
|
| +
|
| + /* If the db->init.busy is 1 it means we are reading the SQL off the
|
| + ** "sqlite_master" or "sqlite_temp_master" table on the disk.
|
| + ** So do not write to the disk again. Extract the root page number
|
| + ** for the table from the db->init.newTnum field. (The page number
|
| + ** should have been put there by the sqliteOpenCb routine.)
|
| + */
|
| + if( db->init.busy ){
|
| + p->tnum = db->init.newTnum;
|
| + }
|
| +
|
| + /* Special processing for WITHOUT ROWID Tables */
|
| + if( tabOpts & TF_WithoutRowid ){
|
| + if( (p->tabFlags & TF_Autoincrement) ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "AUTOINCREMENT not allowed on WITHOUT ROWID tables");
|
| + return;
|
| + }
|
| + if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
|
| + sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName);
|
| + }else{
|
| + p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
|
| + convertToWithoutRowidTable(pParse, p);
|
| + }
|
| + }
|
| +
|
| + iDb = sqlite3SchemaToIndex(db, p->pSchema);
|
| +
|
| +#ifndef SQLITE_OMIT_CHECK
|
| + /* Resolve names in all CHECK constraint expressions.
|
| + */
|
| + if( p->pCheck ){
|
| + sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
|
| + }
|
| +#endif /* !defined(SQLITE_OMIT_CHECK) */
|
| +
|
| + /* Estimate the average row size for the table and for all implied indices */
|
| + estimateTableWidth(p);
|
| + for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + estimateIndexWidth(pIdx);
|
| + }
|
| +
|
| + /* If not initializing, then create a record for the new table
|
| + ** in the SQLITE_MASTER table of the database.
|
| + **
|
| + ** If this is a TEMPORARY table, write the entry into the auxiliary
|
| + ** file instead of into the main database file.
|
| + */
|
| + if( !db->init.busy ){
|
| + int n;
|
| + Vdbe *v;
|
| + char *zType; /* "view" or "table" */
|
| + char *zType2; /* "VIEW" or "TABLE" */
|
| + char *zStmt; /* Text of the CREATE TABLE or CREATE VIEW statement */
|
| +
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( NEVER(v==0) ) return;
|
| +
|
| + sqlite3VdbeAddOp1(v, OP_Close, 0);
|
| +
|
| + /*
|
| + ** Initialize zType for the new view or table.
|
| + */
|
| + if( p->pSelect==0 ){
|
| + /* A regular table */
|
| + zType = "table";
|
| + zType2 = "TABLE";
|
| +#ifndef SQLITE_OMIT_VIEW
|
| + }else{
|
| + /* A view */
|
| + zType = "view";
|
| + zType2 = "VIEW";
|
| +#endif
|
| + }
|
| +
|
| + /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
|
| + ** statement to populate the new table. The root-page number for the
|
| + ** new table is in register pParse->regRoot.
|
| + **
|
| + ** Once the SELECT has been coded by sqlite3Select(), it is in a
|
| + ** suitable state to query for the column names and types to be used
|
| + ** by the new table.
|
| + **
|
| + ** A shared-cache write-lock is not required to write to the new table,
|
| + ** as a schema-lock must have already been obtained to create it. Since
|
| + ** a schema-lock excludes all other database users, the write-lock would
|
| + ** be redundant.
|
| + */
|
| + if( pSelect ){
|
| + SelectDest dest; /* Where the SELECT should store results */
|
| + int regYield; /* Register holding co-routine entry-point */
|
| + int addrTop; /* Top of the co-routine */
|
| + int regRec; /* A record to be insert into the new table */
|
| + int regRowid; /* Rowid of the next row to insert */
|
| + int addrInsLoop; /* Top of the loop for inserting rows */
|
| + Table *pSelTab; /* A table that describes the SELECT results */
|
| +
|
| + regYield = ++pParse->nMem;
|
| + regRec = ++pParse->nMem;
|
| + regRowid = ++pParse->nMem;
|
| + assert(pParse->nTab==1);
|
| + sqlite3MayAbort(pParse);
|
| + sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
|
| + pParse->nTab = 2;
|
| + addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
| + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
| + sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
|
| + sqlite3Select(pParse, pSelect, &dest);
|
| + sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
| + sqlite3VdbeJumpHere(v, addrTop - 1);
|
| + if( pParse->nErr ) return;
|
| + pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
|
| + if( pSelTab==0 ) return;
|
| + assert( p->aCol==0 );
|
| + p->nCol = pSelTab->nCol;
|
| + p->aCol = pSelTab->aCol;
|
| + pSelTab->nCol = 0;
|
| + pSelTab->aCol = 0;
|
| + sqlite3DeleteTable(db, pSelTab);
|
| + addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
| + VdbeCoverage(v);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec);
|
| + sqlite3TableAffinity(v, p, 0);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid);
|
| + sqlite3VdbeGoto(v, addrInsLoop);
|
| + sqlite3VdbeJumpHere(v, addrInsLoop);
|
| + sqlite3VdbeAddOp1(v, OP_Close, 1);
|
| + }
|
| +
|
| + /* Compute the complete text of the CREATE statement */
|
| + if( pSelect ){
|
| + zStmt = createTableStmt(db, p);
|
| + }else{
|
| + Token *pEnd2 = tabOpts ? &pParse->sLastToken : pEnd;
|
| + n = (int)(pEnd2->z - pParse->sNameToken.z);
|
| + if( pEnd2->z[0]!=';' ) n += pEnd2->n;
|
| + zStmt = sqlite3MPrintf(db,
|
| + "CREATE %s %.*s", zType2, n, pParse->sNameToken.z
|
| + );
|
| + }
|
| +
|
| + /* A slot for the record has already been allocated in the
|
| + ** SQLITE_MASTER table. We just need to update that slot with all
|
| + ** the information we've collected.
|
| + */
|
| + sqlite3NestedParse(pParse,
|
| + "UPDATE %Q.%s "
|
| + "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
|
| + "WHERE rowid=#%d",
|
| + db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
| + zType,
|
| + p->zName,
|
| + p->zName,
|
| + pParse->regRoot,
|
| + zStmt,
|
| + pParse->regRowid
|
| + );
|
| + sqlite3DbFree(db, zStmt);
|
| + sqlite3ChangeCookie(pParse, iDb);
|
| +
|
| +#ifndef SQLITE_OMIT_AUTOINCREMENT
|
| + /* Check to see if we need to create an sqlite_sequence table for
|
| + ** keeping track of autoincrement keys.
|
| + */
|
| + if( p->tabFlags & TF_Autoincrement ){
|
| + Db *pDb = &db->aDb[iDb];
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + if( pDb->pSchema->pSeqTab==0 ){
|
| + sqlite3NestedParse(pParse,
|
| + "CREATE TABLE %Q.sqlite_sequence(name,seq)",
|
| + pDb->zName
|
| + );
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* Reparse everything to update our internal data structures */
|
| + sqlite3VdbeAddParseSchemaOp(v, iDb,
|
| + sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
|
| + }
|
| +
|
| +
|
| + /* Add the table to the in-memory representation of the database.
|
| + */
|
| + if( db->init.busy ){
|
| + Table *pOld;
|
| + Schema *pSchema = p->pSchema;
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
|
| + if( pOld ){
|
| + assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
|
| + db->mallocFailed = 1;
|
| + return;
|
| + }
|
| + pParse->pNewTable = 0;
|
| + db->flags |= SQLITE_InternChanges;
|
| +
|
| +#ifndef SQLITE_OMIT_ALTERTABLE
|
| + if( !p->pSelect ){
|
| + const char *zName = (const char *)pParse->sNameToken.z;
|
| + int nName;
|
| + assert( !pSelect && pCons && pEnd );
|
| + if( pCons->z==0 ){
|
| + pCons = pEnd;
|
| + }
|
| + nName = (int)((const char *)pCons->z - zName);
|
| + p->addColOffset = 13 + sqlite3Utf8CharLen(zName, nName);
|
| + }
|
| +#endif
|
| + }
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_VIEW
|
| +/*
|
| +** The parser calls this routine in order to create a new VIEW
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CreateView(
|
| + Parse *pParse, /* The parsing context */
|
| + Token *pBegin, /* The CREATE token that begins the statement */
|
| + Token *pName1, /* The token that holds the name of the view */
|
| + Token *pName2, /* The token that holds the name of the view */
|
| + ExprList *pCNames, /* Optional list of view column names */
|
| + Select *pSelect, /* A SELECT statement that will become the new view */
|
| + int isTemp, /* TRUE for a TEMPORARY view */
|
| + int noErr /* Suppress error messages if VIEW already exists */
|
| +){
|
| + Table *p;
|
| + int n;
|
| + const char *z;
|
| + Token sEnd;
|
| + DbFixer sFix;
|
| + Token *pName = 0;
|
| + int iDb;
|
| + sqlite3 *db = pParse->db;
|
| +
|
| + if( pParse->nVar>0 ){
|
| + sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
|
| + goto create_view_fail;
|
| + }
|
| + sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
|
| + p = pParse->pNewTable;
|
| + if( p==0 || pParse->nErr ) goto create_view_fail;
|
| + sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
| + iDb = sqlite3SchemaToIndex(db, p->pSchema);
|
| + sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
|
| + if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail;
|
| +
|
| + /* Make a copy of the entire SELECT statement that defines the view.
|
| + ** This will force all the Expr.token.z values to be dynamically
|
| + ** allocated rather than point to the input string - which means that
|
| + ** they will persist after the current sqlite3_exec() call returns.
|
| + */
|
| + p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
| + p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
|
| + if( db->mallocFailed ) goto create_view_fail;
|
| +
|
| + /* Locate the end of the CREATE VIEW statement. Make sEnd point to
|
| + ** the end.
|
| + */
|
| + sEnd = pParse->sLastToken;
|
| + assert( sEnd.z[0]!=0 );
|
| + if( sEnd.z[0]!=';' ){
|
| + sEnd.z += sEnd.n;
|
| + }
|
| + sEnd.n = 0;
|
| + n = (int)(sEnd.z - pBegin->z);
|
| + assert( n>0 );
|
| + z = pBegin->z;
|
| + while( sqlite3Isspace(z[n-1]) ){ n--; }
|
| + sEnd.z = &z[n-1];
|
| + sEnd.n = 1;
|
| +
|
| + /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
|
| + sqlite3EndTable(pParse, 0, &sEnd, 0, 0);
|
| +
|
| +create_view_fail:
|
| + sqlite3SelectDelete(db, pSelect);
|
| + sqlite3ExprListDelete(db, pCNames);
|
| + return;
|
| +}
|
| +#endif /* SQLITE_OMIT_VIEW */
|
| +
|
| +#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 */
|
| + sqlite3_xauth xAuth; /* Saved xAuth pointer */
|
| + u8 bEnabledLA; /* Saved db->lookaside.bEnabled state */
|
| +
|
| + assert( pTable );
|
| +
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( sqlite3VtabCallConnect(pParse, pTable) ){
|
| + return SQLITE_ERROR;
|
| + }
|
| + if( IsVirtual(pTable) ) return 0;
|
| +#endif
|
| +
|
| +#ifndef SQLITE_OMIT_VIEW
|
| + /* A positive nCol means the columns names for this view are
|
| + ** already known.
|
| + */
|
| + if( pTable->nCol>0 ) return 0;
|
| +
|
| + /* A negative nCol is a special marker meaning that we are currently
|
| + ** trying to compute the column names. If we enter this routine with
|
| + ** a negative nCol, it means two or more views form a loop, like this:
|
| + **
|
| + ** CREATE VIEW one AS SELECT * FROM two;
|
| + ** CREATE VIEW two AS SELECT * FROM one;
|
| + **
|
| + ** Actually, the error above is now caught prior to reaching this point.
|
| + ** But the following test is still important as it does come up
|
| + ** in the following:
|
| + **
|
| + ** CREATE TABLE main.ex1(a);
|
| + ** CREATE TEMP VIEW ex1 AS SELECT a FROM ex1;
|
| + ** SELECT * FROM temp.ex1;
|
| + */
|
| + 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 );
|
| + bEnabledLA = db->lookaside.bEnabled;
|
| + if( pTable->pCheck ){
|
| + db->lookaside.bEnabled = 0;
|
| + sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
|
| + &pTable->nCol, &pTable->aCol);
|
| + }else{
|
| + pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
|
| + if( pSel ){
|
| + n = pParse->nTab;
|
| + sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
| + pTable->nCol = -1;
|
| + db->lookaside.bEnabled = 0;
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + xAuth = db->xAuth;
|
| + db->xAuth = 0;
|
| + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
| + db->xAuth = xAuth;
|
| +#else
|
| + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
| +#endif
|
| + pParse->nTab = n;
|
| + if( pSelTab ){
|
| + assert( pTable->aCol==0 );
|
| + pTable->nCol = pSelTab->nCol;
|
| + pTable->aCol = pSelTab->aCol;
|
| + pSelTab->nCol = 0;
|
| + pSelTab->aCol = 0;
|
| + sqlite3DeleteTable(db, pSelTab);
|
| + assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
| + }else{
|
| + pTable->nCol = 0;
|
| + nErr++;
|
| + }
|
| + sqlite3SelectDelete(db, pSel);
|
| + } else {
|
| + nErr++;
|
| + }
|
| + }
|
| + db->lookaside.bEnabled = bEnabledLA;
|
| + pTable->pSchema->schemaFlags |= DB_UnresetViews;
|
| +#endif /* SQLITE_OMIT_VIEW */
|
| + return nErr;
|
| +}
|
| +#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
| +
|
| +#ifndef SQLITE_OMIT_VIEW
|
| +/*
|
| +** Clear the column names from every VIEW in database idx.
|
| +*/
|
| +static void sqliteViewResetAll(sqlite3 *db, int idx){
|
| + HashElem *i;
|
| + assert( sqlite3SchemaMutexHeld(db, idx, 0) );
|
| + if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
|
| + for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
|
| + Table *pTab = sqliteHashData(i);
|
| + if( pTab->pSelect ){
|
| + sqlite3DeleteColumnNames(db, pTab);
|
| + pTab->aCol = 0;
|
| + pTab->nCol = 0;
|
| + }
|
| + }
|
| + DbClearProperty(db, idx, DB_UnresetViews);
|
| +}
|
| +#else
|
| +# define sqliteViewResetAll(A,B)
|
| +#endif /* SQLITE_OMIT_VIEW */
|
| +
|
| +/*
|
| +** This function is called by the VDBE to adjust the internal schema
|
| +** used by SQLite when the btree layer moves a table root page. The
|
| +** root-page of a table or index in database iDb has changed from iFrom
|
| +** to iTo.
|
| +**
|
| +** Ticket #1728: The symbol table might still contain information
|
| +** on tables and/or indices that are the process of being deleted.
|
| +** If you are unlucky, one of those deleted indices or tables might
|
| +** have the same rootpage number as the real table or index that is
|
| +** being moved. So we cannot stop searching after the first match
|
| +** because the first match might be for one of the deleted indices
|
| +** or tables and not the table/index that is actually being moved.
|
| +** We must continue looping until all tables and indices with
|
| +** rootpage==iFrom have been converted to have a rootpage of iTo
|
| +** in order to be certain that we got the right one.
|
| +*/
|
| +#ifndef SQLITE_OMIT_AUTOVACUUM
|
| +SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
|
| + HashElem *pElem;
|
| + Hash *pHash;
|
| + Db *pDb;
|
| +
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + pDb = &db->aDb[iDb];
|
| + pHash = &pDb->pSchema->tblHash;
|
| + for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
|
| + Table *pTab = sqliteHashData(pElem);
|
| + if( pTab->tnum==iFrom ){
|
| + pTab->tnum = iTo;
|
| + }
|
| + }
|
| + pHash = &pDb->pSchema->idxHash;
|
| + for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
|
| + Index *pIdx = sqliteHashData(pElem);
|
| + if( pIdx->tnum==iFrom ){
|
| + pIdx->tnum = iTo;
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** Write code to erase the table with root-page iTable from database iDb.
|
| +** Also write code to modify the sqlite_master table and internal schema
|
| +** if a root-page of another table is moved by the btree-layer whilst
|
| +** erasing iTable (this can happen with an auto-vacuum database).
|
| +*/
|
| +static void destroyRootPage(Parse *pParse, int iTable, int iDb){
|
| + Vdbe *v = sqlite3GetVdbe(pParse);
|
| + int r1 = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
|
| + sqlite3MayAbort(pParse);
|
| +#ifndef SQLITE_OMIT_AUTOVACUUM
|
| + /* OP_Destroy stores an in integer r1. If this integer
|
| + ** is non-zero, then it is the root page number of a table moved to
|
| + ** location iTable. The following code modifies the sqlite_master table to
|
| + ** reflect this.
|
| + **
|
| + ** The "#NNN" in the SQL is a special constant that means whatever value
|
| + ** is in register NNN. See grammar rules associated with the TK_REGISTER
|
| + ** token for additional information.
|
| + */
|
| + sqlite3NestedParse(pParse,
|
| + "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
|
| + pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
|
| +#endif
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| +}
|
| +
|
| +/*
|
| +** Write VDBE code to erase table pTab and all associated indices on disk.
|
| +** Code to update the sqlite_master tables and internal schema definitions
|
| +** in case a root-page belonging to another table is moved by the btree layer
|
| +** is also added (this can happen with an auto-vacuum database).
|
| +*/
|
| +static void destroyTable(Parse *pParse, Table *pTab){
|
| +#ifdef SQLITE_OMIT_AUTOVACUUM
|
| + Index *pIdx;
|
| + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
| + destroyRootPage(pParse, pTab->tnum, iDb);
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + destroyRootPage(pParse, pIdx->tnum, iDb);
|
| + }
|
| +#else
|
| + /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
|
| + ** is not defined), then it is important to call OP_Destroy on the
|
| + ** table and index root-pages in order, starting with the numerically
|
| + ** largest root-page number. This guarantees that none of the root-pages
|
| + ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
|
| + ** following were coded:
|
| + **
|
| + ** OP_Destroy 4 0
|
| + ** ...
|
| + ** OP_Destroy 5 0
|
| + **
|
| + ** and root page 5 happened to be the largest root-page number in the
|
| + ** database, then root page 5 would be moved to page 4 by the
|
| + ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
|
| + ** a free-list page.
|
| + */
|
| + int iTab = pTab->tnum;
|
| + int iDestroyed = 0;
|
| +
|
| + while( 1 ){
|
| + Index *pIdx;
|
| + int iLargest = 0;
|
| +
|
| + if( iDestroyed==0 || iTab<iDestroyed ){
|
| + iLargest = iTab;
|
| + }
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + int iIdx = pIdx->tnum;
|
| + assert( pIdx->pSchema==pTab->pSchema );
|
| + if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
|
| + iLargest = iIdx;
|
| + }
|
| + }
|
| + if( iLargest==0 ){
|
| + return;
|
| + }else{
|
| + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
| + assert( iDb>=0 && iDb<pParse->db->nDb );
|
| + destroyRootPage(pParse, iLargest, iDb);
|
| + iDestroyed = iLargest;
|
| + }
|
| + }
|
| +#endif
|
| +}
|
| +
|
| +/*
|
| +** Remove entries from the sqlite_statN tables (for N in (1,2,3))
|
| +** after a DROP INDEX or DROP TABLE command.
|
| +*/
|
| +static void sqlite3ClearStatTables(
|
| + Parse *pParse, /* The parsing context */
|
| + int iDb, /* The database number */
|
| + const char *zType, /* "idx" or "tbl" */
|
| + const char *zName /* Name of index or table */
|
| +){
|
| + int i;
|
| + const char *zDbName = pParse->db->aDb[iDb].zName;
|
| + for(i=1; i<=4; i++){
|
| + char zTab[24];
|
| + sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
|
| + if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
|
| + sqlite3NestedParse(pParse,
|
| + "DELETE FROM %Q.%s WHERE %s=%Q",
|
| + zDbName, zTab, zType, zName
|
| + );
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Generate code to drop a table.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
| + Vdbe *v;
|
| + sqlite3 *db = pParse->db;
|
| + Trigger *pTrigger;
|
| + Db *pDb = &db->aDb[iDb];
|
| +
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( v!=0 );
|
| + sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| +
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( IsVirtual(pTab) ){
|
| + sqlite3VdbeAddOp0(v, OP_VBegin);
|
| + }
|
| +#endif
|
| +
|
| + /* Drop all triggers associated with the table being dropped. Code
|
| + ** is generated to remove entries from sqlite_master and/or
|
| + ** sqlite_temp_master if required.
|
| + */
|
| + pTrigger = sqlite3TriggerList(pParse, pTab);
|
| + while( pTrigger ){
|
| + assert( pTrigger->pSchema==pTab->pSchema ||
|
| + pTrigger->pSchema==db->aDb[1].pSchema );
|
| + sqlite3DropTriggerPtr(pParse, pTrigger);
|
| + pTrigger = pTrigger->pNext;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_AUTOINCREMENT
|
| + /* Remove any entries of the sqlite_sequence table associated with
|
| + ** the table being dropped. This is done before the table is dropped
|
| + ** at the btree level, in case the sqlite_sequence table needs to
|
| + ** move as a result of the drop (can happen in auto-vacuum mode).
|
| + */
|
| + if( pTab->tabFlags & TF_Autoincrement ){
|
| + sqlite3NestedParse(pParse,
|
| + "DELETE FROM %Q.sqlite_sequence WHERE name=%Q",
|
| + pDb->zName, pTab->zName
|
| + );
|
| + }
|
| +#endif
|
| +
|
| + /* Drop all SQLITE_MASTER table and index entries that refer to the
|
| + ** table. The program name loops through the master table and deletes
|
| + ** every row that refers to a table of the same name as the one being
|
| + ** dropped. Triggers are handled separately because a trigger can be
|
| + ** created in the temp database that refers to a table in another
|
| + ** database.
|
| + */
|
| + sqlite3NestedParse(pParse,
|
| + "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
|
| + pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
|
| + if( !isView && !IsVirtual(pTab) ){
|
| + destroyTable(pParse, pTab);
|
| + }
|
| +
|
| + /* Remove the table entry from SQLite's internal schema and modify
|
| + ** the schema cookie.
|
| + */
|
| + if( IsVirtual(pTab) ){
|
| + sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0);
|
| + }
|
| + sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
|
| + sqlite3ChangeCookie(pParse, iDb);
|
| + sqliteViewResetAll(db, iDb);
|
| +}
|
| +
|
| +/*
|
| +** This routine is called to do the work of a DROP TABLE statement.
|
| +** pName is the name of the table to be dropped.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
| + Table *pTab;
|
| + Vdbe *v;
|
| + sqlite3 *db = pParse->db;
|
| + int iDb;
|
| +
|
| + if( db->mallocFailed ){
|
| + goto exit_drop_table;
|
| + }
|
| + assert( pParse->nErr==0 );
|
| + assert( pName->nSrc==1 );
|
| + if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
| + if( noErr ) db->suppressErr++;
|
| + pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
|
| + if( noErr ) db->suppressErr--;
|
| +
|
| + if( pTab==0 ){
|
| + if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
| + goto exit_drop_table;
|
| + }
|
| + iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| + assert( iDb>=0 && iDb<db->nDb );
|
| +
|
| + /* If pTab is a virtual table, call ViewGetColumnNames() to ensure
|
| + ** it is initialized.
|
| + */
|
| + if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
|
| + goto exit_drop_table;
|
| + }
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + {
|
| + int code;
|
| + const char *zTab = SCHEMA_TABLE(iDb);
|
| + const char *zDb = db->aDb[iDb].zName;
|
| + const char *zArg2 = 0;
|
| + if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
|
| + goto exit_drop_table;
|
| + }
|
| + if( isView ){
|
| + if( !OMIT_TEMPDB && iDb==1 ){
|
| + code = SQLITE_DROP_TEMP_VIEW;
|
| + }else{
|
| + code = SQLITE_DROP_VIEW;
|
| + }
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + }else if( IsVirtual(pTab) ){
|
| + code = SQLITE_DROP_VTABLE;
|
| + zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
|
| +#endif
|
| + }else{
|
| + if( !OMIT_TEMPDB && iDb==1 ){
|
| + code = SQLITE_DROP_TEMP_TABLE;
|
| + }else{
|
| + code = SQLITE_DROP_TABLE;
|
| + }
|
| + }
|
| + if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
|
| + goto exit_drop_table;
|
| + }
|
| + if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
|
| + goto exit_drop_table;
|
| + }
|
| + }
|
| +#endif
|
| + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
| + && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){
|
| + sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
| + goto exit_drop_table;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_VIEW
|
| + /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
|
| + ** on a table.
|
| + */
|
| + if( isView && pTab->pSelect==0 ){
|
| + sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
|
| + goto exit_drop_table;
|
| + }
|
| + if( !isView && pTab->pSelect ){
|
| + sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
|
| + goto exit_drop_table;
|
| + }
|
| +#endif
|
| +
|
| + /* Generate code to remove the table from the master table
|
| + ** on disk.
|
| + */
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v ){
|
| + sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| + sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
|
| + sqlite3FkDropTable(pParse, pName, pTab);
|
| + sqlite3CodeDropTable(pParse, pTab, iDb, isView);
|
| + }
|
| +
|
| +exit_drop_table:
|
| + sqlite3SrcListDelete(db, pName);
|
| +}
|
| +
|
| +/*
|
| +** This routine is called to create a new foreign key on the table
|
| +** currently under construction. pFromCol determines which columns
|
| +** in the current table point to the foreign key. If pFromCol==0 then
|
| +** connect the key to the last column inserted. pTo is the name of
|
| +** the table referred to (a.k.a the "parent" table). pToCol is a list
|
| +** of tables in the parent pTo table. flags contains all
|
| +** information about the conflict resolution algorithms specified
|
| +** in the ON DELETE, ON UPDATE and ON INSERT clauses.
|
| +**
|
| +** An FKey structure is created and added to the table currently
|
| +** under construction in the pParse->pNewTable field.
|
| +**
|
| +** The foreign key is set for IMMEDIATE processing. A subsequent call
|
| +** to sqlite3DeferForeignKey() might change this to DEFERRED.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CreateForeignKey(
|
| + Parse *pParse, /* Parsing context */
|
| + ExprList *pFromCol, /* Columns in this table that point to other table */
|
| + Token *pTo, /* Name of the other table */
|
| + ExprList *pToCol, /* Columns in the other table */
|
| + int flags /* Conflict resolution algorithms. */
|
| +){
|
| + sqlite3 *db = pParse->db;
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| + FKey *pFKey = 0;
|
| + FKey *pNextTo;
|
| + Table *p = pParse->pNewTable;
|
| + int nByte;
|
| + int i;
|
| + int nCol;
|
| + char *z;
|
| +
|
| + assert( pTo!=0 );
|
| + if( p==0 || IN_DECLARE_VTAB ) goto fk_end;
|
| + if( pFromCol==0 ){
|
| + int iCol = p->nCol-1;
|
| + if( NEVER(iCol<0) ) goto fk_end;
|
| + if( pToCol && pToCol->nExpr!=1 ){
|
| + sqlite3ErrorMsg(pParse, "foreign key on %s"
|
| + " should reference only one column of table %T",
|
| + p->aCol[iCol].zName, pTo);
|
| + goto fk_end;
|
| + }
|
| + nCol = 1;
|
| + }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "number of columns in foreign key does not match the number of "
|
| + "columns in the referenced table");
|
| + goto fk_end;
|
| + }else{
|
| + nCol = pFromCol->nExpr;
|
| + }
|
| + nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
|
| + if( pToCol ){
|
| + for(i=0; i<pToCol->nExpr; i++){
|
| + nByte += sqlite3Strlen30(pToCol->a[i].zName) + 1;
|
| + }
|
| + }
|
| + pFKey = sqlite3DbMallocZero(db, nByte );
|
| + if( pFKey==0 ){
|
| + goto fk_end;
|
| + }
|
| + pFKey->pFrom = p;
|
| + pFKey->pNextFrom = p->pFKey;
|
| + z = (char*)&pFKey->aCol[nCol];
|
| + pFKey->zTo = z;
|
| + memcpy(z, pTo->z, pTo->n);
|
| + z[pTo->n] = 0;
|
| + sqlite3Dequote(z);
|
| + z += pTo->n+1;
|
| + pFKey->nCol = nCol;
|
| + if( pFromCol==0 ){
|
| + pFKey->aCol[0].iFrom = p->nCol-1;
|
| + }else{
|
| + for(i=0; i<nCol; i++){
|
| + int j;
|
| + for(j=0; j<p->nCol; j++){
|
| + if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
|
| + pFKey->aCol[i].iFrom = j;
|
| + break;
|
| + }
|
| + }
|
| + if( j>=p->nCol ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "unknown column \"%s\" in foreign key definition",
|
| + pFromCol->a[i].zName);
|
| + goto fk_end;
|
| + }
|
| + }
|
| + }
|
| + if( pToCol ){
|
| + for(i=0; i<nCol; i++){
|
| + int n = sqlite3Strlen30(pToCol->a[i].zName);
|
| + pFKey->aCol[i].zCol = z;
|
| + memcpy(z, pToCol->a[i].zName, n);
|
| + z[n] = 0;
|
| + z += n+1;
|
| + }
|
| + }
|
| + pFKey->isDeferred = 0;
|
| + pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */
|
| + pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */
|
| +
|
| + assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
|
| + pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
|
| + pFKey->zTo, (void *)pFKey
|
| + );
|
| + if( pNextTo==pFKey ){
|
| + db->mallocFailed = 1;
|
| + goto fk_end;
|
| + }
|
| + if( pNextTo ){
|
| + assert( pNextTo->pPrevTo==0 );
|
| + pFKey->pNextTo = pNextTo;
|
| + pNextTo->pPrevTo = pFKey;
|
| + }
|
| +
|
| + /* Link the foreign key to the table as the last step.
|
| + */
|
| + p->pFKey = pFKey;
|
| + pFKey = 0;
|
| +
|
| +fk_end:
|
| + sqlite3DbFree(db, pFKey);
|
| +#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
|
| + sqlite3ExprListDelete(db, pFromCol);
|
| + sqlite3ExprListDelete(db, pToCol);
|
| +}
|
| +
|
| +/*
|
| +** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED
|
| +** clause is seen as part of a foreign key definition. The isDeferred
|
| +** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE.
|
| +** The behavior of the most recently created foreign key is adjusted
|
| +** accordingly.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| + Table *pTab;
|
| + FKey *pFKey;
|
| + if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return;
|
| + assert( isDeferred==0 || isDeferred==1 ); /* EV: R-30323-21917 */
|
| + pFKey->isDeferred = (u8)isDeferred;
|
| +#endif
|
| +}
|
| +
|
| +/*
|
| +** Generate code that will erase and refill index *pIdx. This is
|
| +** used to initialize a newly created index or to recompute the
|
| +** 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++; /* Btree cursor used for pIndex */
|
| + int iSorter; /* Cursor opened by OpenSorter (if in use) */
|
| + int addr1; /* Address of top of loop */
|
| + int addr2; /* Address to jump to for next iteration */
|
| + int tnum; /* Root page of index */
|
| + int iPartIdxLabel; /* Jump to this label to skip a row */
|
| + Vdbe *v; /* Generate code into this virtual machine */
|
| + KeyInfo *pKey; /* KeyInfo for index */
|
| + int regRecord; /* Register holding assembled index record */
|
| + sqlite3 *db = pParse->db; /* The database connection */
|
| + int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
| +
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
|
| + db->aDb[iDb].zName ) ){
|
| + return;
|
| + }
|
| +#endif
|
| +
|
| + /* Require a write-lock on the table to perform this operation */
|
| + sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
|
| +
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v==0 ) return;
|
| + if( memRootPage>=0 ){
|
| + tnum = memRootPage;
|
| + }else{
|
| + tnum = pIndex->tnum;
|
| + }
|
| + pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
|
| +
|
| + /* Open the sorter cursor if we are to use one. */
|
| + iSorter = pParse->nTab++;
|
| + sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*)
|
| + sqlite3KeyInfoRef(pKey), P4_KEYINFO);
|
| +
|
| + /* Open the table. Loop through all rows of the table, inserting index
|
| + ** records into the sorter. */
|
| + sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
|
| + regRecord = sqlite3GetTempReg(pParse);
|
| +
|
| + sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
|
| + sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
|
| + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
| + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
|
| + sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
|
| + (char *)pKey, P4_KEYINFO);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
|
| +
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
|
| + assert( pKey!=0 || db->mallocFailed || pParse->nErr );
|
| + if( IsUniqueIndex(pIndex) && pKey!=0 ){
|
| + int j2 = sqlite3VdbeCurrentAddr(v) + 3;
|
| + sqlite3VdbeGoto(v, j2);
|
| + addr2 = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
|
| + pIndex->nKeyCol); VdbeCoverage(v);
|
| + sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
|
| + }else{
|
| + addr2 = sqlite3VdbeCurrentAddr(v);
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
|
| + sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
|
| + sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
| + sqlite3ReleaseTempReg(pParse, regRecord);
|
| + sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| +
|
| + sqlite3VdbeAddOp1(v, OP_Close, iTab);
|
| + sqlite3VdbeAddOp1(v, OP_Close, iIdx);
|
| + sqlite3VdbeAddOp1(v, OP_Close, iSorter);
|
| +}
|
| +
|
| +/*
|
| +** Allocate heap space to hold an Index object with nCol columns.
|
| +**
|
| +** Increase the allocation size to provide an extra nExtra bytes
|
| +** of 8-byte aligned space after the Index object and return a
|
| +** pointer to this extra space in *ppExtra.
|
| +*/
|
| +SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
|
| + sqlite3 *db, /* Database connection */
|
| + i16 nCol, /* Total number of columns in the index */
|
| + int nExtra, /* Number of bytes of extra space to alloc */
|
| + char **ppExtra /* Pointer to the "extra" space */
|
| +){
|
| + Index *p; /* Allocated index object */
|
| + int nByte; /* Bytes of space for Index object + arrays */
|
| +
|
| + nByte = ROUND8(sizeof(Index)) + /* Index structure */
|
| + ROUND8(sizeof(char*)*nCol) + /* Index.azColl */
|
| + ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */
|
| + sizeof(i16)*nCol + /* Index.aiColumn */
|
| + sizeof(u8)*nCol); /* Index.aSortOrder */
|
| + p = sqlite3DbMallocZero(db, nByte + nExtra);
|
| + if( p ){
|
| + char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
|
| + p->azColl = (const char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
|
| + p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
|
| + p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
|
| + p->aSortOrder = (u8*)pExtra;
|
| + p->nColumn = nCol;
|
| + p->nKeyCol = nCol - 1;
|
| + *ppExtra = ((char*)p) + nByte;
|
| + }
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** Create a new index for an SQL table. pName1.pName2 is the name of the index
|
| +** and pTblList is the name of the table that is to be indexed. Both will
|
| +** be NULL for a primary key or an index that is created to satisfy a
|
| +** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable
|
| +** as the table to be indexed. pParse->pNewTable is a table that is
|
| +** currently being constructed by a CREATE TABLE statement.
|
| +**
|
| +** pList is a list of columns to be indexed. pList will be NULL if this
|
| +** is a primary key or unique-constraint on the most recent column added
|
| +** to the table currently under construction.
|
| +**
|
| +** If the index is created successfully, return a pointer to the new Index
|
| +** structure. This is used by sqlite3AddPrimaryKey() to mark the index
|
| +** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY)
|
| +*/
|
| +SQLITE_PRIVATE Index *sqlite3CreateIndex(
|
| + Parse *pParse, /* All information about this parse */
|
| + Token *pName1, /* First part of index name. May be NULL */
|
| + Token *pName2, /* Second part of index name. May be NULL */
|
| + SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */
|
| + ExprList *pList, /* A list of columns to be indexed */
|
| + int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
| + Token *pStart, /* The CREATE token that begins this statement */
|
| + Expr *pPIWhere, /* WHERE clause for partial indices */
|
| + int sortOrder, /* Sort order of primary key when pList==NULL */
|
| + int ifNotExist /* Omit error if index already exists */
|
| +){
|
| + Index *pRet = 0; /* Pointer to return */
|
| + Table *pTab = 0; /* Table to be indexed */
|
| + Index *pIndex = 0; /* The index to be created */
|
| + char *zName = 0; /* Name of the index */
|
| + int nName; /* Number of characters in zName */
|
| + int i, j;
|
| + DbFixer sFix; /* For assigning database names to pTable */
|
| + int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */
|
| + sqlite3 *db = pParse->db;
|
| + Db *pDb; /* The specific table containing the indexed database */
|
| + int iDb; /* Index of the database that is being written */
|
| + Token *pName = 0; /* Unqualified name of the index to create */
|
| + struct ExprList_item *pListItem; /* For looping over pList */
|
| + int nExtra = 0; /* Space allocated for zExtra[] */
|
| + int nExtraCol; /* Number of extra columns needed */
|
| + char *zExtra = 0; /* Extra space after the Index object */
|
| + Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
|
| +
|
| + if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){
|
| + goto exit_create_index;
|
| + }
|
| + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
| + goto exit_create_index;
|
| + }
|
| +
|
| + /*
|
| + ** Find the table that is to be indexed. Return early if not found.
|
| + */
|
| + if( pTblName!=0 ){
|
| +
|
| + /* Use the two-part index name to determine the database
|
| + ** to search for the table. 'Fix' the table name to this db
|
| + ** before looking up the table.
|
| + */
|
| + assert( pName1 && pName2 );
|
| + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
| + if( iDb<0 ) goto exit_create_index;
|
| + assert( pName && pName->z );
|
| +
|
| +#ifndef SQLITE_OMIT_TEMPDB
|
| + /* If the index name was unqualified, check if the table
|
| + ** is a temp table. If so, set the database to 1. Do not do this
|
| + ** if initialising a database schema.
|
| + */
|
| + if( !db->init.busy ){
|
| + pTab = sqlite3SrcListLookup(pParse, pTblName);
|
| + if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
|
| + iDb = 1;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + sqlite3FixInit(&sFix, pParse, iDb, "index", pName);
|
| + if( sqlite3FixSrcList(&sFix, pTblName) ){
|
| + /* Because the parser constructs pTblName from a single identifier,
|
| + ** sqlite3FixSrcList can never fail. */
|
| + assert(0);
|
| + }
|
| + pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
|
| + assert( db->mallocFailed==0 || pTab==0 );
|
| + if( pTab==0 ) goto exit_create_index;
|
| + if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "cannot create a TEMP index on non-TEMP table \"%s\"",
|
| + pTab->zName);
|
| + goto exit_create_index;
|
| + }
|
| + if( !HasRowid(pTab) ) pPk = sqlite3PrimaryKeyIndex(pTab);
|
| + }else{
|
| + assert( pName==0 );
|
| + assert( pStart==0 );
|
| + pTab = pParse->pNewTable;
|
| + if( !pTab ) goto exit_create_index;
|
| + iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| + }
|
| + pDb = &db->aDb[iDb];
|
| +
|
| + assert( pTab!=0 );
|
| + assert( pParse->nErr==0 );
|
| + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
| + && db->init.busy==0
|
| +#if SQLITE_USER_AUTHENTICATION
|
| + && sqlite3UserAuthTable(pTab->zName)==0
|
| +#endif
|
| + && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
|
| + sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
|
| + goto exit_create_index;
|
| + }
|
| +#ifndef SQLITE_OMIT_VIEW
|
| + if( pTab->pSelect ){
|
| + sqlite3ErrorMsg(pParse, "views may not be indexed");
|
| + goto exit_create_index;
|
| + }
|
| +#endif
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( IsVirtual(pTab) ){
|
| + sqlite3ErrorMsg(pParse, "virtual tables may not be indexed");
|
| + goto exit_create_index;
|
| + }
|
| +#endif
|
| +
|
| + /*
|
| + ** Find the name of the index. Make sure there is not already another
|
| + ** index or table with the same name.
|
| + **
|
| + ** Exception: If we are reading the names of permanent indices from the
|
| + ** sqlite_master table (because some other process changed the schema) and
|
| + ** one of the index names collides with the name of a temporary table or
|
| + ** index, then we will continue to process this index.
|
| + **
|
| + ** If pName==0 it means that we are
|
| + ** dealing with a primary key or UNIQUE constraint. We have to invent our
|
| + ** own name.
|
| + */
|
| + if( pName ){
|
| + zName = sqlite3NameFromToken(db, pName);
|
| + if( zName==0 ) goto exit_create_index;
|
| + assert( pName->z!=0 );
|
| + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
| + goto exit_create_index;
|
| + }
|
| + if( !db->init.busy ){
|
| + if( sqlite3FindTable(db, zName, 0)!=0 ){
|
| + sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
| + goto exit_create_index;
|
| + }
|
| + }
|
| + if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
|
| + if( !ifNotExist ){
|
| + sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
| + }else{
|
| + assert( !db->init.busy );
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + }
|
| + goto exit_create_index;
|
| + }
|
| + }else{
|
| + int n;
|
| + Index *pLoop;
|
| + for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
|
| + zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n);
|
| + if( zName==0 ){
|
| + goto exit_create_index;
|
| + }
|
| + }
|
| +
|
| + /* Check for authorization to create an index.
|
| + */
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + {
|
| + const char *zDb = pDb->zName;
|
| + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
|
| + goto exit_create_index;
|
| + }
|
| + i = SQLITE_CREATE_INDEX;
|
| + if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX;
|
| + if( sqlite3AuthCheck(pParse, i, zName, pTab->zName, zDb) ){
|
| + goto exit_create_index;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* If pList==0, it means this routine was called to make a primary
|
| + ** key out of the last column added to the table under construction.
|
| + ** So create a fake list to simulate this.
|
| + */
|
| + if( pList==0 ){
|
| + Token prevCol;
|
| + prevCol.z = pTab->aCol[pTab->nCol-1].zName;
|
| + prevCol.n = sqlite3Strlen30(prevCol.z);
|
| + pList = sqlite3ExprListAppend(pParse, 0,
|
| + sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
|
| + if( pList==0 ) goto exit_create_index;
|
| + assert( pList->nExpr==1 );
|
| + sqlite3ExprListSetSortOrder(pList, sortOrder);
|
| + }else{
|
| + sqlite3ExprListCheckLength(pParse, pList, "index");
|
| + }
|
| +
|
| + /* Figure out how many bytes of space are required to store explicitly
|
| + ** specified collation sequence names.
|
| + */
|
| + for(i=0; i<pList->nExpr; i++){
|
| + Expr *pExpr = pList->a[i].pExpr;
|
| + assert( pExpr!=0 );
|
| + if( pExpr->op==TK_COLLATE ){
|
| + nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
|
| + }
|
| + }
|
| +
|
| + /*
|
| + ** Allocate the index structure.
|
| + */
|
| + nName = sqlite3Strlen30(zName);
|
| + nExtraCol = pPk ? pPk->nKeyCol : 1;
|
| + pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol,
|
| + nName + nExtra + 1, &zExtra);
|
| + if( db->mallocFailed ){
|
| + goto exit_create_index;
|
| + }
|
| + assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) );
|
| + assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
|
| + pIndex->zName = zExtra;
|
| + zExtra += nName + 1;
|
| + memcpy(pIndex->zName, zName, nName+1);
|
| + pIndex->pTable = pTab;
|
| + pIndex->onError = (u8)onError;
|
| + pIndex->uniqNotNull = onError!=OE_None;
|
| + pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE;
|
| + pIndex->pSchema = db->aDb[iDb].pSchema;
|
| + pIndex->nKeyCol = pList->nExpr;
|
| + if( pPIWhere ){
|
| + sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0);
|
| + pIndex->pPartIdxWhere = pPIWhere;
|
| + pPIWhere = 0;
|
| + }
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| +
|
| + /* Check to see if we should honor DESC requests on index columns
|
| + */
|
| + if( pDb->pSchema->file_format>=4 ){
|
| + sortOrderMask = -1; /* Honor DESC */
|
| + }else{
|
| + sortOrderMask = 0; /* Ignore DESC */
|
| + }
|
| +
|
| + /* Analyze the list of expressions that form the terms of the index and
|
| + ** report any errors. In the common case where the expression is exactly
|
| + ** a table column, store that column in aiColumn[]. For general expressions,
|
| + ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[].
|
| + **
|
| + ** TODO: Issue a warning if two or more columns of the index are identical.
|
| + ** TODO: Issue a warning if the table primary key is used as part of the
|
| + ** index key.
|
| + */
|
| + for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
|
| + Expr *pCExpr; /* The i-th index expression */
|
| + int requestedSortOrder; /* ASC or DESC on the i-th expression */
|
| + const char *zColl; /* Collation sequence name */
|
| +
|
| + sqlite3StringToId(pListItem->pExpr);
|
| + sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0);
|
| + if( pParse->nErr ) goto exit_create_index;
|
| + pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr);
|
| + if( pCExpr->op!=TK_COLUMN ){
|
| + if( pTab==pParse->pNewTable ){
|
| + sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and "
|
| + "UNIQUE constraints");
|
| + goto exit_create_index;
|
| + }
|
| + if( pIndex->aColExpr==0 ){
|
| + ExprList *pCopy = sqlite3ExprListDup(db, pList, 0);
|
| + pIndex->aColExpr = pCopy;
|
| + if( !db->mallocFailed ){
|
| + assert( pCopy!=0 );
|
| + pListItem = &pCopy->a[i];
|
| + }
|
| + }
|
| + j = XN_EXPR;
|
| + pIndex->aiColumn[i] = XN_EXPR;
|
| + pIndex->uniqNotNull = 0;
|
| + }else{
|
| + j = pCExpr->iColumn;
|
| + assert( j<=0x7fff );
|
| + if( j<0 ){
|
| + j = pTab->iPKey;
|
| + }else if( pTab->aCol[j].notNull==0 ){
|
| + pIndex->uniqNotNull = 0;
|
| + }
|
| + pIndex->aiColumn[i] = (i16)j;
|
| + }
|
| + zColl = 0;
|
| + if( pListItem->pExpr->op==TK_COLLATE ){
|
| + int nColl;
|
| + zColl = pListItem->pExpr->u.zToken;
|
| + nColl = sqlite3Strlen30(zColl) + 1;
|
| + assert( nExtra>=nColl );
|
| + memcpy(zExtra, zColl, nColl);
|
| + zColl = zExtra;
|
| + zExtra += nColl;
|
| + nExtra -= nColl;
|
| + }else if( j>=0 ){
|
| + zColl = pTab->aCol[j].zColl;
|
| + }
|
| + if( !zColl ) zColl = sqlite3StrBINARY;
|
| + if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
|
| + goto exit_create_index;
|
| + }
|
| + pIndex->azColl[i] = zColl;
|
| + requestedSortOrder = pListItem->sortOrder & sortOrderMask;
|
| + pIndex->aSortOrder[i] = (u8)requestedSortOrder;
|
| + }
|
| +
|
| + /* Append the table key to the end of the index. For WITHOUT ROWID
|
| + ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For
|
| + ** normal tables (when pPk==0) this will be the rowid.
|
| + */
|
| + if( pPk ){
|
| + for(j=0; j<pPk->nKeyCol; j++){
|
| + int x = pPk->aiColumn[j];
|
| + assert( x>=0 );
|
| + if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){
|
| + pIndex->nColumn--;
|
| + }else{
|
| + pIndex->aiColumn[i] = x;
|
| + pIndex->azColl[i] = pPk->azColl[j];
|
| + pIndex->aSortOrder[i] = pPk->aSortOrder[j];
|
| + i++;
|
| + }
|
| + }
|
| + assert( i==pIndex->nColumn );
|
| + }else{
|
| + pIndex->aiColumn[i] = XN_ROWID;
|
| + pIndex->azColl[i] = sqlite3StrBINARY;
|
| + }
|
| + sqlite3DefaultRowEst(pIndex);
|
| + if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
|
| +
|
| + if( pTab==pParse->pNewTable ){
|
| + /* This routine has been called to create an automatic index as a
|
| + ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
|
| + ** a PRIMARY KEY or UNIQUE clause following the column definitions.
|
| + ** i.e. one of:
|
| + **
|
| + ** CREATE TABLE t(x PRIMARY KEY, y);
|
| + ** CREATE TABLE t(x, y, UNIQUE(x, y));
|
| + **
|
| + ** Either way, check to see if the table already has such an index. If
|
| + ** so, don't bother creating this one. This only applies to
|
| + ** automatically created indices. Users can do as they wish with
|
| + ** explicit indices.
|
| + **
|
| + ** Two UNIQUE or PRIMARY KEY constraints are considered equivalent
|
| + ** (and thus suppressing the second one) even if they have different
|
| + ** sort orders.
|
| + **
|
| + ** If there are different collating sequences or if the columns of
|
| + ** the constraint occur in different orders, then the constraints are
|
| + ** considered distinct and both result in separate indices.
|
| + */
|
| + Index *pIdx;
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + int k;
|
| + assert( IsUniqueIndex(pIdx) );
|
| + assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF );
|
| + assert( IsUniqueIndex(pIndex) );
|
| +
|
| + if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue;
|
| + for(k=0; k<pIdx->nKeyCol; k++){
|
| + const char *z1;
|
| + const char *z2;
|
| + assert( pIdx->aiColumn[k]>=0 );
|
| + if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
|
| + z1 = pIdx->azColl[k];
|
| + z2 = pIndex->azColl[k];
|
| + if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
|
| + }
|
| + if( k==pIdx->nKeyCol ){
|
| + if( pIdx->onError!=pIndex->onError ){
|
| + /* This constraint creates the same index as a previous
|
| + ** constraint specified somewhere in the CREATE TABLE statement.
|
| + ** However the ON CONFLICT clauses are different. If both this
|
| + ** constraint and the previous equivalent constraint have explicit
|
| + ** ON CONFLICT clauses this is an error. Otherwise, use the
|
| + ** explicitly specified behavior for the index.
|
| + */
|
| + if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "conflicting ON CONFLICT clauses specified", 0);
|
| + }
|
| + if( pIdx->onError==OE_Default ){
|
| + pIdx->onError = pIndex->onError;
|
| + }
|
| + }
|
| + pRet = pIdx;
|
| + goto exit_create_index;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Link the new Index structure to its table and to the other
|
| + ** in-memory database structures.
|
| + */
|
| + assert( pParse->nErr==0 );
|
| + if( db->init.busy ){
|
| + Index *p;
|
| + assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
| + p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
| + pIndex->zName, pIndex);
|
| + if( p ){
|
| + assert( p==pIndex ); /* Malloc must have failed */
|
| + db->mallocFailed = 1;
|
| + goto exit_create_index;
|
| + }
|
| + db->flags |= SQLITE_InternChanges;
|
| + if( pTblName!=0 ){
|
| + pIndex->tnum = db->init.newTnum;
|
| + }
|
| + }
|
| +
|
| + /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
|
| + ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
|
| + ** emit code to allocate the index rootpage on disk and make an entry for
|
| + ** the index in the sqlite_master table and populate the index with
|
| + ** content. But, do not do this if we are simply reading the sqlite_master
|
| + ** table to parse the schema, or if this index is the PRIMARY KEY index
|
| + ** of a WITHOUT ROWID table.
|
| + **
|
| + ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY
|
| + ** or UNIQUE index in a CREATE TABLE statement. Since the table
|
| + ** has just been created, it contains no data and the index initialization
|
| + ** step can be skipped.
|
| + */
|
| + else if( HasRowid(pTab) || pTblName!=0 ){
|
| + Vdbe *v;
|
| + char *zStmt;
|
| + int iMem = ++pParse->nMem;
|
| +
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v==0 ) goto exit_create_index;
|
| +
|
| + sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| +
|
| + /* Create the rootpage for the index using CreateIndex. But before
|
| + ** doing so, code a Noop instruction and store its address in
|
| + ** Index.tnum. This is required in case this index is actually a
|
| + ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
|
| + ** that case the convertToWithoutRowidTable() routine will replace
|
| + ** the Noop with a Goto to jump over the VDBE code generated below. */
|
| + pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
|
| + sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
|
| +
|
| + /* Gather the complete text of the CREATE INDEX statement into
|
| + ** the zStmt variable
|
| + */
|
| + if( pStart ){
|
| + int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
| + if( pName->z[n-1]==';' ) n--;
|
| + /* A named index with an explicit CREATE INDEX statement */
|
| + zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
|
| + onError==OE_None ? "" : " UNIQUE", n, pName->z);
|
| + }else{
|
| + /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
|
| + /* zStmt = sqlite3MPrintf(""); */
|
| + zStmt = 0;
|
| + }
|
| +
|
| + /* Add an entry in sqlite_master for this index
|
| + */
|
| + sqlite3NestedParse(pParse,
|
| + "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
|
| + db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
| + pIndex->zName,
|
| + pTab->zName,
|
| + iMem,
|
| + zStmt
|
| + );
|
| + sqlite3DbFree(db, zStmt);
|
| +
|
| + /* Fill the index with data and reparse the schema. Code an OP_Expire
|
| + ** to invalidate all pre-compiled statements.
|
| + */
|
| + if( pTblName ){
|
| + sqlite3RefillIndex(pParse, pIndex, iMem);
|
| + sqlite3ChangeCookie(pParse, iDb);
|
| + sqlite3VdbeAddParseSchemaOp(v, iDb,
|
| + sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
|
| + sqlite3VdbeAddOp1(v, OP_Expire, 0);
|
| + }
|
| +
|
| + sqlite3VdbeJumpHere(v, pIndex->tnum);
|
| + }
|
| +
|
| + /* When adding an index to the list of indices for a table, make
|
| + ** sure all indices labeled OE_Replace come after all those labeled
|
| + ** OE_Ignore. This is necessary for the correct constraint check
|
| + ** processing (in sqlite3GenerateConstraintChecks()) as part of
|
| + ** UPDATE and INSERT statements.
|
| + */
|
| + if( db->init.busy || pTblName==0 ){
|
| + if( onError!=OE_Replace || pTab->pIndex==0
|
| + || pTab->pIndex->onError==OE_Replace){
|
| + pIndex->pNext = pTab->pIndex;
|
| + pTab->pIndex = pIndex;
|
| + }else{
|
| + Index *pOther = pTab->pIndex;
|
| + while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
|
| + pOther = pOther->pNext;
|
| + }
|
| + pIndex->pNext = pOther->pNext;
|
| + pOther->pNext = pIndex;
|
| + }
|
| + pRet = pIndex;
|
| + pIndex = 0;
|
| + }
|
| +
|
| + /* Clean up before exiting */
|
| +exit_create_index:
|
| + if( pIndex ) freeIndex(db, pIndex);
|
| + sqlite3ExprDelete(db, pPIWhere);
|
| + sqlite3ExprListDelete(db, pList);
|
| + sqlite3SrcListDelete(db, pTblName);
|
| + sqlite3DbFree(db, zName);
|
| + return pRet;
|
| +}
|
| +
|
| +/*
|
| +** Fill the Index.aiRowEst[] array with default information - information
|
| +** to be used when we have not run the ANALYZE command.
|
| +**
|
| +** aiRowEst[0] is supposed to contain the number of elements in the index.
|
| +** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the
|
| +** number of rows in the table that match any particular value of the
|
| +** first column of the index. aiRowEst[2] is an estimate of the number
|
| +** of rows that match any particular combination of the first 2 columns
|
| +** of the index. And so forth. It must always be the case that
|
| +*
|
| +** aiRowEst[N]<=aiRowEst[N-1]
|
| +** aiRowEst[N]>=1
|
| +**
|
| +** Apart from that, we have little to go on besides intuition as to
|
| +** how aiRowEst[] should be initialized. The numbers generated here
|
| +** are based on typical values found in actual indices.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){
|
| + /* 10, 9, 8, 7, 6 */
|
| + LogEst aVal[] = { 33, 32, 30, 28, 26 };
|
| + LogEst *a = pIdx->aiRowLogEst;
|
| + int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
|
| + int i;
|
| +
|
| + /* Set the first entry (number of rows in the index) to the estimated
|
| + ** number of rows in the table. Or 10, if the estimated number of rows
|
| + ** in the table is less than that. */
|
| + a[0] = pIdx->pTable->nRowLogEst;
|
| + if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
| +
|
| + /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
|
| + ** 6 and each subsequent value (if any) is 5. */
|
| + memcpy(&a[1], aVal, nCopy*sizeof(LogEst));
|
| + for(i=nCopy+1; i<=pIdx->nKeyCol; i++){
|
| + a[i] = 23; assert( 23==sqlite3LogEst(5) );
|
| + }
|
| +
|
| + assert( 0==sqlite3LogEst(1) );
|
| + if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0;
|
| +}
|
| +
|
| +/*
|
| +** This routine will drop an existing named index. This routine
|
| +** implements the DROP INDEX statement.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
| + Index *pIndex;
|
| + Vdbe *v;
|
| + sqlite3 *db = pParse->db;
|
| + int iDb;
|
| +
|
| + assert( pParse->nErr==0 ); /* Never called with prior errors */
|
| + if( db->mallocFailed ){
|
| + goto exit_drop_index;
|
| + }
|
| + assert( pName->nSrc==1 );
|
| + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
| + goto exit_drop_index;
|
| + }
|
| + pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
|
| + if( pIndex==0 ){
|
| + if( !ifExists ){
|
| + sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
|
| + }else{
|
| + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
| + }
|
| + pParse->checkSchema = 1;
|
| + goto exit_drop_index;
|
| + }
|
| + if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
|
| + sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
|
| + "or PRIMARY KEY constraint cannot be dropped", 0);
|
| + goto exit_drop_index;
|
| + }
|
| + iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + {
|
| + int code = SQLITE_DROP_INDEX;
|
| + Table *pTab = pIndex->pTable;
|
| + const char *zDb = db->aDb[iDb].zName;
|
| + const char *zTab = SCHEMA_TABLE(iDb);
|
| + if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
| + goto exit_drop_index;
|
| + }
|
| + if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX;
|
| + if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
|
| + goto exit_drop_index;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* Generate code to remove the index and from the master table */
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v ){
|
| + sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| + sqlite3NestedParse(pParse,
|
| + "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
|
| + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName
|
| + );
|
| + sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
|
| + sqlite3ChangeCookie(pParse, iDb);
|
| + destroyRootPage(pParse, pIndex->tnum, iDb);
|
| + sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);
|
| + }
|
| +
|
| +exit_drop_index:
|
| + sqlite3SrcListDelete(db, pName);
|
| +}
|
| +
|
| +/*
|
| +** pArray is a pointer to an array of objects. Each object in the
|
| +** array is szEntry bytes in size. This routine uses sqlite3DbRealloc()
|
| +** to extend the array so that there is space for a new object at the end.
|
| +**
|
| +** When this function is called, *pnEntry contains the current size of
|
| +** the array (in entries - so the allocation is ((*pnEntry) * szEntry) bytes
|
| +** in total).
|
| +**
|
| +** If the realloc() is successful (i.e. if no OOM condition occurs), the
|
| +** space allocated for the new object is zeroed, *pnEntry updated to
|
| +** reflect the new size of the array and a pointer to the new allocation
|
| +** returned. *pIdx is set to the index of the new array entry in this case.
|
| +**
|
| +** Otherwise, if the realloc() fails, *pIdx is set to -1, *pnEntry remains
|
| +** unchanged and a copy of pArray returned.
|
| +*/
|
| +SQLITE_PRIVATE void *sqlite3ArrayAllocate(
|
| + sqlite3 *db, /* Connection to notify of malloc failures */
|
| + void *pArray, /* Array of objects. Might be reallocated */
|
| + int szEntry, /* Size of each object in the array */
|
| + int *pnEntry, /* Number of objects currently in use */
|
| + int *pIdx /* Write the index of a new slot here */
|
| +){
|
| + char *z;
|
| + int n = *pnEntry;
|
| + if( (n & (n-1))==0 ){
|
| + int sz = (n==0) ? 1 : 2*n;
|
| + void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry);
|
| + if( pNew==0 ){
|
| + *pIdx = -1;
|
| + return pArray;
|
| + }
|
| + pArray = pNew;
|
| + }
|
| + z = (char*)pArray;
|
| + memset(&z[n * szEntry], 0, szEntry);
|
| + *pIdx = n;
|
| + ++*pnEntry;
|
| + return pArray;
|
| +}
|
| +
|
| +/*
|
| +** Append a new element to the given IdList. Create a new IdList if
|
| +** need be.
|
| +**
|
| +** A new IdList is returned, or NULL if malloc() fails.
|
| +*/
|
| +SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
|
| + int i;
|
| + if( pList==0 ){
|
| + pList = sqlite3DbMallocZero(db, sizeof(IdList) );
|
| + if( pList==0 ) return 0;
|
| + }
|
| + pList->a = sqlite3ArrayAllocate(
|
| + db,
|
| + pList->a,
|
| + sizeof(pList->a[0]),
|
| + &pList->nId,
|
| + &i
|
| + );
|
| + if( i<0 ){
|
| + sqlite3IdListDelete(db, pList);
|
| + return 0;
|
| + }
|
| + pList->a[i].zName = sqlite3NameFromToken(db, pToken);
|
| + return pList;
|
| +}
|
| +
|
| +/*
|
| +** Delete an IdList.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
|
| + int i;
|
| + if( pList==0 ) return;
|
| + for(i=0; i<pList->nId; i++){
|
| + sqlite3DbFree(db, pList->a[i].zName);
|
| + }
|
| + sqlite3DbFree(db, pList->a);
|
| + sqlite3DbFree(db, pList);
|
| +}
|
| +
|
| +/*
|
| +** Return the index in pList of the identifier named zId. Return -1
|
| +** if not found.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){
|
| + int i;
|
| + if( pList==0 ) return -1;
|
| + for(i=0; i<pList->nId; i++){
|
| + if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i;
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| +/*
|
| +** Expand the space allocated for the given SrcList object by
|
| +** creating nExtra new slots beginning at iStart. iStart is zero based.
|
| +** New slots are zeroed.
|
| +**
|
| +** For example, suppose a SrcList initially contains two entries: A,B.
|
| +** To append 3 new entries onto the end, do this:
|
| +**
|
| +** sqlite3SrcListEnlarge(db, pSrclist, 3, 2);
|
| +**
|
| +** After the call above it would contain: A, B, nil, nil, nil.
|
| +** If the iStart argument had been 1 instead of 2, then the result
|
| +** would have been: A, nil, nil, nil, B. To prepend the new slots,
|
| +** the iStart value would be 0. The result then would
|
| +** be: nil, nil, nil, A, B.
|
| +**
|
| +** If a memory allocation fails the SrcList is unchanged. The
|
| +** db->mallocFailed flag will be set to true.
|
| +*/
|
| +SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
|
| + sqlite3 *db, /* Database connection to notify of OOM errors */
|
| + SrcList *pSrc, /* The SrcList to be enlarged */
|
| + int nExtra, /* Number of new slots to add to pSrc->a[] */
|
| + int iStart /* Index in pSrc->a[] of first new slot */
|
| +){
|
| + int i;
|
| +
|
| + /* Sanity checking on calling parameters */
|
| + assert( iStart>=0 );
|
| + assert( nExtra>=1 );
|
| + assert( pSrc!=0 );
|
| + assert( iStart<=pSrc->nSrc );
|
| +
|
| + /* Allocate additional space if needed */
|
| + if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
|
| + SrcList *pNew;
|
| + int nAlloc = pSrc->nSrc+nExtra;
|
| + int nGot;
|
| + pNew = sqlite3DbRealloc(db, pSrc,
|
| + sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
|
| + if( pNew==0 ){
|
| + assert( db->mallocFailed );
|
| + return pSrc;
|
| + }
|
| + pSrc = pNew;
|
| + nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1;
|
| + pSrc->nAlloc = nGot;
|
| + }
|
| +
|
| + /* Move existing slots that come after the newly inserted slots
|
| + ** out of the way */
|
| + for(i=pSrc->nSrc-1; i>=iStart; i--){
|
| + pSrc->a[i+nExtra] = pSrc->a[i];
|
| + }
|
| + pSrc->nSrc += nExtra;
|
| +
|
| + /* Zero the newly allocated slots */
|
| + memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra);
|
| + for(i=iStart; i<iStart+nExtra; i++){
|
| + pSrc->a[i].iCursor = -1;
|
| + }
|
| +
|
| + /* Return a pointer to the enlarged SrcList */
|
| + return pSrc;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Append a new table name to the given SrcList. Create a new SrcList if
|
| +** need be. A new entry is created in the SrcList even if pTable is NULL.
|
| +**
|
| +** A SrcList is returned, or NULL if there is an OOM error. The returned
|
| +** SrcList might be the same as the SrcList that was input or it might be
|
| +** a new one. If an OOM error does occurs, then the prior value of pList
|
| +** that is input to this routine is automatically freed.
|
| +**
|
| +** If pDatabase is not null, it means that the table has an optional
|
| +** database name prefix. Like this: "database.table". The pDatabase
|
| +** points to the table name and the pTable points to the database name.
|
| +** The SrcList.a[].zName field is filled with the table name which might
|
| +** come from pTable (if pDatabase is NULL) or from pDatabase.
|
| +** SrcList.a[].zDatabase is filled with the database name from pTable,
|
| +** or with NULL if no database is specified.
|
| +**
|
| +** In other words, if call like this:
|
| +**
|
| +** sqlite3SrcListAppend(D,A,B,0);
|
| +**
|
| +** Then B is a table name and the database name is unspecified. If called
|
| +** like this:
|
| +**
|
| +** sqlite3SrcListAppend(D,A,B,C);
|
| +**
|
| +** Then C is the table name and B is the database name. If C is defined
|
| +** then so is B. In other words, we never have a case where:
|
| +**
|
| +** sqlite3SrcListAppend(D,A,0,C);
|
| +**
|
| +** Both pTable and pDatabase are assumed to be quoted. They are dequoted
|
| +** before being added to the SrcList.
|
| +*/
|
| +SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
|
| + sqlite3 *db, /* Connection to notify of malloc failures */
|
| + SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */
|
| + Token *pTable, /* Table to append */
|
| + Token *pDatabase /* Database of the table */
|
| +){
|
| + struct SrcList_item *pItem;
|
| + assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
|
| + if( pList==0 ){
|
| + pList = sqlite3DbMallocZero(db, sizeof(SrcList) );
|
| + if( pList==0 ) return 0;
|
| + pList->nAlloc = 1;
|
| + }
|
| + pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
|
| + if( db->mallocFailed ){
|
| + sqlite3SrcListDelete(db, pList);
|
| + return 0;
|
| + }
|
| + pItem = &pList->a[pList->nSrc-1];
|
| + if( pDatabase && pDatabase->z==0 ){
|
| + pDatabase = 0;
|
| + }
|
| + if( pDatabase ){
|
| + Token *pTemp = pDatabase;
|
| + pDatabase = pTable;
|
| + pTable = pTemp;
|
| + }
|
| + pItem->zName = sqlite3NameFromToken(db, pTable);
|
| + pItem->zDatabase = sqlite3NameFromToken(db, pDatabase);
|
| + return pList;
|
| +}
|
| +
|
| +/*
|
| +** Assign VdbeCursor index numbers 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 ){
|
| + sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Delete an entire SrcList including all its substructure.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
| + int i;
|
| + struct SrcList_item *pItem;
|
| + if( pList==0 ) return;
|
| + for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
|
| + sqlite3DbFree(db, pItem->zDatabase);
|
| + sqlite3DbFree(db, pItem->zName);
|
| + sqlite3DbFree(db, pItem->zAlias);
|
| + if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
|
| + if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
|
| + sqlite3DeleteTable(db, pItem->pTab);
|
| + sqlite3SelectDelete(db, pItem->pSelect);
|
| + sqlite3ExprDelete(db, pItem->pOn);
|
| + sqlite3IdListDelete(db, pItem->pUsing);
|
| + }
|
| + sqlite3DbFree(db, pList);
|
| +}
|
| +
|
| +/*
|
| +** This routine is called by the parser to add a new term to the
|
| +** end of a growing FROM clause. The "p" parameter is the part of
|
| +** the FROM clause that has already been constructed. "p" is NULL
|
| +** if this is the first term of the FROM clause. pTable and pDatabase
|
| +** are the name of the table and database named in the FROM clause term.
|
| +** pDatabase is NULL if the database name qualifier is missing - the
|
| +** usual case. If the term has an alias, then pAlias points to the
|
| +** alias token. If the term is a subquery, then pSubquery is the
|
| +** SELECT statement that the subquery encodes. The pTable and
|
| +** pDatabase parameters are NULL for subqueries. The pOn and pUsing
|
| +** parameters are the content of the ON and USING clauses.
|
| +**
|
| +** Return a new SrcList which encodes is the FROM with the new
|
| +** term added.
|
| +*/
|
| +SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
|
| + Parse *pParse, /* Parsing context */
|
| + SrcList *p, /* The left part of the FROM clause already seen */
|
| + Token *pTable, /* Name of the table to add to the FROM clause */
|
| + Token *pDatabase, /* Name of the database containing pTable */
|
| + Token *pAlias, /* The right-hand side of the AS subexpression */
|
| + Select *pSubquery, /* A subquery used in place of a table name */
|
| + Expr *pOn, /* The ON clause of a join */
|
| + IdList *pUsing /* The USING clause of a join */
|
| +){
|
| + struct SrcList_item *pItem;
|
| + sqlite3 *db = pParse->db;
|
| + if( !p && (pOn || pUsing) ){
|
| + sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
|
| + (pOn ? "ON" : "USING")
|
| + );
|
| + goto append_from_error;
|
| + }
|
| + p = sqlite3SrcListAppend(db, p, pTable, pDatabase);
|
| + if( p==0 || NEVER(p->nSrc==0) ){
|
| + goto append_from_error;
|
| + }
|
| + pItem = &p->a[p->nSrc-1];
|
| + assert( pAlias!=0 );
|
| + if( pAlias->n ){
|
| + pItem->zAlias = sqlite3NameFromToken(db, pAlias);
|
| + }
|
| + pItem->pSelect = pSubquery;
|
| + pItem->pOn = pOn;
|
| + pItem->pUsing = pUsing;
|
| + return p;
|
| +
|
| + append_from_error:
|
| + assert( p==0 );
|
| + sqlite3ExprDelete(db, pOn);
|
| + sqlite3IdListDelete(db, pUsing);
|
| + sqlite3SelectDelete(db, pSubquery);
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** Add an INDEXED BY or NOT INDEXED clause to the most recently added
|
| +** element of the source-list passed as the second argument.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
|
| + assert( pIndexedBy!=0 );
|
| + if( p && ALWAYS(p->nSrc>0) ){
|
| + struct SrcList_item *pItem = &p->a[p->nSrc-1];
|
| + assert( pItem->fg.notIndexed==0 );
|
| + assert( pItem->fg.isIndexedBy==0 );
|
| + assert( pItem->fg.isTabFunc==0 );
|
| + if( pIndexedBy->n==1 && !pIndexedBy->z ){
|
| + /* A "NOT INDEXED" clause was supplied. See parse.y
|
| + ** construct "indexed_opt" for details. */
|
| + pItem->fg.notIndexed = 1;
|
| + }else{
|
| + pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
|
| + pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Add the list of function arguments to the SrcList entry for a
|
| +** table-valued-function.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
|
| + if( p ){
|
| + struct SrcList_item *pItem = &p->a[p->nSrc-1];
|
| + assert( pItem->fg.notIndexed==0 );
|
| + assert( pItem->fg.isIndexedBy==0 );
|
| + assert( pItem->fg.isTabFunc==0 );
|
| + pItem->u1.pFuncArg = pList;
|
| + pItem->fg.isTabFunc = 1;
|
| + }else{
|
| + sqlite3ExprListDelete(pParse->db, pList);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** When building up a FROM clause in the parser, the join operator
|
| +** is initially attached to the left operand. But the code generator
|
| +** expects the join operator to be on the right operand. This routine
|
| +** Shifts all join operators from left to right for an entire FROM
|
| +** clause.
|
| +**
|
| +** Example: Suppose the join is like this:
|
| +**
|
| +** A natural cross join B
|
| +**
|
| +** The operator is "natural cross join". The A and B operands are stored
|
| +** in p->a[0] and p->a[1], respectively. The parser initially stores the
|
| +** operator with A. This routine shifts that operator over to B.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){
|
| + if( p ){
|
| + int i;
|
| + for(i=p->nSrc-1; i>0; i--){
|
| + p->a[i].fg.jointype = p->a[i-1].fg.jointype;
|
| + }
|
| + p->a[0].fg.jointype = 0;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Begin a transaction
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
|
| + sqlite3 *db;
|
| + Vdbe *v;
|
| + int i;
|
| +
|
| + assert( pParse!=0 );
|
| + db = pParse->db;
|
| + assert( db!=0 );
|
| +/* if( db->aDb[0].pBt==0 ) return; */
|
| + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){
|
| + return;
|
| + }
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( !v ) return;
|
| + if( type!=TK_DEFERRED ){
|
| + for(i=0; i<db->nDb; i++){
|
| + sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
|
| + sqlite3VdbeUsesBtree(v, i);
|
| + }
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_AutoCommit, 0, 0);
|
| +}
|
| +
|
| +/*
|
| +** Commit a transaction
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){
|
| + Vdbe *v;
|
| +
|
| + assert( pParse!=0 );
|
| + assert( pParse->db!=0 );
|
| + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){
|
| + return;
|
| + }
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v ){
|
| + sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 0);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Rollback a transaction
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){
|
| + Vdbe *v;
|
| +
|
| + assert( pParse!=0 );
|
| + assert( pParse->db!=0 );
|
| + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){
|
| + return;
|
| + }
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v ){
|
| + sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This function is called by the parser when it parses a command to create,
|
| +** release or rollback an SQL savepoint.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3Savepoint(Parse *pParse, int op, Token *pName){
|
| + char *zName = sqlite3NameFromToken(pParse->db, pName);
|
| + if( zName ){
|
| + Vdbe *v = sqlite3GetVdbe(pParse);
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + static const char * const az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
|
| + assert( !SAVEPOINT_BEGIN && SAVEPOINT_RELEASE==1 && SAVEPOINT_ROLLBACK==2 );
|
| +#endif
|
| + if( !v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0) ){
|
| + sqlite3DbFree(pParse->db, zName);
|
| + return;
|
| + }
|
| + sqlite3VdbeAddOp4(v, OP_Savepoint, op, 0, 0, zName, P4_DYNAMIC);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Make sure the TEMP database is open and available for use. Return
|
| +** the number of errors. Leave any error messages in the pParse structure.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
|
| + sqlite3 *db = pParse->db;
|
| + if( db->aDb[1].pBt==0 && !pParse->explain ){
|
| + int rc;
|
| + Btree *pBt;
|
| + static const int flags =
|
| + SQLITE_OPEN_READWRITE |
|
| + SQLITE_OPEN_CREATE |
|
| + SQLITE_OPEN_EXCLUSIVE |
|
| + SQLITE_OPEN_DELETEONCLOSE |
|
| + SQLITE_OPEN_TEMP_DB;
|
| +
|
| + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags);
|
| + if( rc!=SQLITE_OK ){
|
| + sqlite3ErrorMsg(pParse, "unable to open a temporary database "
|
| + "file for storing temporary tables");
|
| + pParse->rc = rc;
|
| + return 1;
|
| + }
|
| + db->aDb[1].pBt = pBt;
|
| + assert( db->aDb[1].pSchema );
|
| + if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
|
| + db->mallocFailed = 1;
|
| + return 1;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** Record the fact that the schema cookie will need to be verified
|
| +** for database iDb. The code to actually verify the schema cookie
|
| +** will occur at the end of the top-level VDBE and will be generated
|
| +** later, by sqlite3FinishCoding().
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
| + Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + sqlite3 *db = pToplevel->db;
|
| +
|
| + assert( iDb>=0 && iDb<db->nDb );
|
| + assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
| + assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
|
| + DbMaskSet(pToplevel->cookieMask, iDb);
|
| + pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
| + if( !OMIT_TEMPDB && iDb==1 ){
|
| + sqlite3OpenTempDatabase(pToplevel);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each
|
| +** attached database. Otherwise, invoke it for the database named zDb only.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){
|
| + sqlite3 *db = pParse->db;
|
| + int i;
|
| + for(i=0; i<db->nDb; i++){
|
| + Db *pDb = &db->aDb[i];
|
| + if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){
|
| + sqlite3CodeVerifySchema(pParse, i);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Generate VDBE code that prepares for doing an operation that
|
| +** might change the database.
|
| +**
|
| +** This routine starts a new transaction if we are not already within
|
| +** a transaction. If we are already within a transaction, then a checkpoint
|
| +** is set if the setStatement parameter is true. A checkpoint should
|
| +** be set for operations that might fail (due to a constraint) part of
|
| +** the way through and which will need to undo some writes without having to
|
| +** rollback the whole transaction. For operations where all constraints
|
| +** can be checked before any changes are made to the database, it is never
|
| +** necessary to undo a write and the checkpoint should not be set.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
|
| + Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + DbMaskSet(pToplevel->writeMask, iDb);
|
| + pToplevel->isMultiWrite |= setStatement;
|
| +}
|
| +
|
| +/*
|
| +** Indicate that the statement currently under construction might write
|
| +** more than one entry (example: deleting one row then inserting another,
|
| +** inserting multiple rows in a table, or inserting a row and index entries.)
|
| +** If an abort occurs after some of these writes have completed, then it will
|
| +** be necessary to undo the completed writes.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){
|
| + Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + pToplevel->isMultiWrite = 1;
|
| +}
|
| +
|
| +/*
|
| +** The code generator calls this routine if is discovers that it is
|
| +** possible to abort a statement prior to completion. In order to
|
| +** perform this abort without corrupting the database, we need to make
|
| +** sure that the statement is protected by a statement transaction.
|
| +**
|
| +** Technically, we only need to set the mayAbort flag if the
|
| +** isMultiWrite flag was previously set. There is a time dependency
|
| +** such that the abort must occur after the multiwrite. This makes
|
| +** some statements involving the REPLACE conflict resolution algorithm
|
| +** go a little faster. But taking advantage of this time dependency
|
| +** makes it more difficult to prove that the code is correct (in
|
| +** particular, it prevents us from writing an effective
|
| +** implementation of sqlite3AssertMayAbort()) and so we have chosen
|
| +** to take the safe route and skip the optimization.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3MayAbort(Parse *pParse){
|
| + Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + pToplevel->mayAbort = 1;
|
| +}
|
| +
|
| +/*
|
| +** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT
|
| +** error. The onError parameter determines which (if any) of the statement
|
| +** and/or current transaction is rolled back.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3HaltConstraint(
|
| + Parse *pParse, /* Parsing context */
|
| + int errCode, /* extended error code */
|
| + int onError, /* Constraint type */
|
| + char *p4, /* Error message */
|
| + i8 p4type, /* P4_STATIC or P4_TRANSIENT */
|
| + u8 p5Errmsg /* P5_ErrMsg type */
|
| +){
|
| + Vdbe *v = sqlite3GetVdbe(pParse);
|
| + assert( (errCode&0xff)==SQLITE_CONSTRAINT );
|
| + if( onError==OE_Abort ){
|
| + sqlite3MayAbort(pParse);
|
| + }
|
| + sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
|
| + if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg);
|
| +}
|
| +
|
| +/*
|
| +** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3UniqueConstraint(
|
| + Parse *pParse, /* Parsing context */
|
| + int onError, /* Constraint type */
|
| + Index *pIdx /* The index that triggers the constraint */
|
| +){
|
| + char *zErr;
|
| + int j;
|
| + StrAccum errMsg;
|
| + Table *pTab = pIdx->pTable;
|
| +
|
| + sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
|
| + if( pIdx->aColExpr ){
|
| + sqlite3XPrintf(&errMsg, 0, "index '%q'", pIdx->zName);
|
| + }else{
|
| + for(j=0; j<pIdx->nKeyCol; j++){
|
| + char *zCol;
|
| + assert( pIdx->aiColumn[j]>=0 );
|
| + zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
|
| + if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
|
| + sqlite3XPrintf(&errMsg, 0, "%s.%s", pTab->zName, zCol);
|
| + }
|
| + }
|
| + zErr = sqlite3StrAccumFinish(&errMsg);
|
| + sqlite3HaltConstraint(pParse,
|
| + IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY
|
| + : SQLITE_CONSTRAINT_UNIQUE,
|
| + onError, zErr, P4_DYNAMIC, P5_ConstraintUnique);
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Code an OP_Halt due to non-unique rowid.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3RowidConstraint(
|
| + Parse *pParse, /* Parsing context */
|
| + int onError, /* Conflict resolution algorithm */
|
| + Table *pTab /* The table with the non-unique rowid */
|
| +){
|
| + char *zMsg;
|
| + int rc;
|
| + if( pTab->iPKey>=0 ){
|
| + zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName,
|
| + pTab->aCol[pTab->iPKey].zName);
|
| + rc = SQLITE_CONSTRAINT_PRIMARYKEY;
|
| + }else{
|
| + zMsg = sqlite3MPrintf(pParse->db, "%s.rowid", pTab->zName);
|
| + rc = SQLITE_CONSTRAINT_ROWID;
|
| + }
|
| + sqlite3HaltConstraint(pParse, rc, onError, zMsg, P4_DYNAMIC,
|
| + P5_ConstraintUnique);
|
| +}
|
| +
|
| +/*
|
| +** Check to see if pIndex uses the collating sequence pColl. Return
|
| +** true if it does and false if it does not.
|
| +*/
|
| +#ifndef SQLITE_OMIT_REINDEX
|
| +static int collationMatch(const char *zColl, Index *pIndex){
|
| + int i;
|
| + assert( zColl!=0 );
|
| + for(i=0; i<pIndex->nColumn; i++){
|
| + const char *z = pIndex->azColl[i];
|
| + assert( z!=0 || pIndex->aiColumn[i]<0 );
|
| + if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){
|
| + return 1;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** Recompute all indices of pTab that use the collating sequence pColl.
|
| +** If pColl==0 then recompute all indices of pTab.
|
| +*/
|
| +#ifndef SQLITE_OMIT_REINDEX
|
| +static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
|
| + Index *pIndex; /* An index associated with pTab */
|
| +
|
| + for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
|
| + if( zColl==0 || collationMatch(zColl, pIndex) ){
|
| + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
| + sqlite3BeginWriteOperation(pParse, 0, iDb);
|
| + sqlite3RefillIndex(pParse, pIndex, -1);
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** Recompute all indices of all tables in all databases where the
|
| +** indices use the collating sequence pColl. If pColl==0 then recompute
|
| +** all indices everywhere.
|
| +*/
|
| +#ifndef SQLITE_OMIT_REINDEX
|
| +static void reindexDatabases(Parse *pParse, char const *zColl){
|
| + Db *pDb; /* A single database */
|
| + int iDb; /* The database index number */
|
| + sqlite3 *db = pParse->db; /* The database connection */
|
| + HashElem *k; /* For looping over tables in pDb */
|
| + Table *pTab; /* A table in the database */
|
| +
|
| + assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */
|
| + for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
|
| + assert( pDb!=0 );
|
| + for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
|
| + pTab = (Table*)sqliteHashData(k);
|
| + reindexTable(pParse, pTab, zColl);
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** Generate code for the REINDEX command.
|
| +**
|
| +** REINDEX -- 1
|
| +** REINDEX <collation> -- 2
|
| +** REINDEX ?<database>.?<tablename> -- 3
|
| +** REINDEX ?<database>.?<indexname> -- 4
|
| +**
|
| +** Form 1 causes all indices in all attached databases to be rebuilt.
|
| +** Form 2 rebuilds all indices in all databases that use the named
|
| +** collating function. Forms 3 and 4 rebuild the named index or all
|
| +** indices associated with the named table.
|
| +*/
|
| +#ifndef SQLITE_OMIT_REINDEX
|
| +SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
|
| + CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */
|
| + char *z; /* Name of a table or index */
|
| + const char *zDb; /* Name of the database */
|
| + Table *pTab; /* A table in the database */
|
| + Index *pIndex; /* An index associated with pTab */
|
| + int iDb; /* The database index number */
|
| + sqlite3 *db = pParse->db; /* The database connection */
|
| + Token *pObjName; /* Name of the table or index to be reindexed */
|
| +
|
| + /* Read the database schema. If an error occurs, leave an error message
|
| + ** and code in pParse and return NULL. */
|
| + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
| + return;
|
| + }
|
| +
|
| + if( pName1==0 ){
|
| + reindexDatabases(pParse, 0);
|
| + return;
|
| + }else if( NEVER(pName2==0) || pName2->z==0 ){
|
| + char *zColl;
|
| + assert( pName1->z );
|
| + zColl = sqlite3NameFromToken(pParse->db, pName1);
|
| + if( !zColl ) return;
|
| + pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
|
| + if( pColl ){
|
| + reindexDatabases(pParse, zColl);
|
| + sqlite3DbFree(db, zColl);
|
| + return;
|
| + }
|
| + sqlite3DbFree(db, zColl);
|
| + }
|
| + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
|
| + if( iDb<0 ) return;
|
| + z = sqlite3NameFromToken(db, pObjName);
|
| + if( z==0 ) return;
|
| + zDb = db->aDb[iDb].zName;
|
| + pTab = sqlite3FindTable(db, z, zDb);
|
| + if( pTab ){
|
| + reindexTable(pParse, pTab, 0);
|
| + sqlite3DbFree(db, z);
|
| + return;
|
| + }
|
| + pIndex = sqlite3FindIndex(db, z, zDb);
|
| + sqlite3DbFree(db, z);
|
| + if( pIndex ){
|
| + sqlite3BeginWriteOperation(pParse, 0, iDb);
|
| + sqlite3RefillIndex(pParse, pIndex, -1);
|
| + return;
|
| + }
|
| + sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** Return a KeyInfo structure that is appropriate for the given Index.
|
| +**
|
| +** The KeyInfo structure for an index is cached in the Index object.
|
| +** So there might be multiple references to the returned pointer. The
|
| +** caller should not try to modify the KeyInfo object.
|
| +**
|
| +** The caller should invoke sqlite3KeyInfoUnref() on the returned object
|
| +** when it has finished using it.
|
| +*/
|
| +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
|
| + int i;
|
| + int nCol = pIdx->nColumn;
|
| + int nKey = pIdx->nKeyCol;
|
| + KeyInfo *pKey;
|
| + if( pParse->nErr ) return 0;
|
| + if( pIdx->uniqNotNull ){
|
| + pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
|
| + }else{
|
| + pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
|
| + }
|
| + if( pKey ){
|
| + assert( sqlite3KeyInfoIsWriteable(pKey) );
|
| + for(i=0; i<nCol; i++){
|
| + const char *zColl = pIdx->azColl[i];
|
| + pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 :
|
| + sqlite3LocateCollSeq(pParse, zColl);
|
| + pKey->aSortOrder[i] = pIdx->aSortOrder[i];
|
| + }
|
| + if( pParse->nErr ){
|
| + sqlite3KeyInfoUnref(pKey);
|
| + pKey = 0;
|
| + }
|
| + }
|
| + return pKey;
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_CTE
|
| +/*
|
| +** This routine is invoked once per CTE by the parser while parsing a
|
| +** WITH clause.
|
| +*/
|
| +SQLITE_PRIVATE With *sqlite3WithAdd(
|
| + Parse *pParse, /* Parsing context */
|
| + With *pWith, /* Existing WITH clause, or NULL */
|
| + Token *pName, /* Name of the common-table */
|
| + ExprList *pArglist, /* Optional column name list for the table */
|
| + Select *pQuery /* Query used to initialize the table */
|
| +){
|
| + sqlite3 *db = pParse->db;
|
| + With *pNew;
|
| + char *zName;
|
| +
|
| + /* Check that the CTE name is unique within this WITH clause. If
|
| + ** not, store an error in the Parse structure. */
|
| + zName = sqlite3NameFromToken(pParse->db, pName);
|
| + if( zName && pWith ){
|
| + int i;
|
| + for(i=0; i<pWith->nCte; i++){
|
| + if( sqlite3StrICmp(zName, pWith->a[i].zName)==0 ){
|
| + sqlite3ErrorMsg(pParse, "duplicate WITH table name: %s", zName);
|
| + }
|
| + }
|
| + }
|
| +
|
| + if( pWith ){
|
| + int nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte);
|
| + pNew = sqlite3DbRealloc(db, pWith, nByte);
|
| + }else{
|
| + pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
|
| + }
|
| + assert( zName!=0 || pNew==0 );
|
| + assert( db->mallocFailed==0 || pNew==0 );
|
| +
|
| + if( pNew==0 ){
|
| + sqlite3ExprListDelete(db, pArglist);
|
| + sqlite3SelectDelete(db, pQuery);
|
| + sqlite3DbFree(db, zName);
|
| + pNew = pWith;
|
| + }else{
|
| + pNew->a[pNew->nCte].pSelect = pQuery;
|
| + pNew->a[pNew->nCte].pCols = pArglist;
|
| + pNew->a[pNew->nCte].zName = zName;
|
| + pNew->a[pNew->nCte].zCteErr = 0;
|
| + pNew->nCte++;
|
| + }
|
| +
|
| + return pNew;
|
| +}
|
| +
|
| +/*
|
| +** Free the contents of the With object passed as the second argument.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){
|
| + if( pWith ){
|
| + int i;
|
| + for(i=0; i<pWith->nCte; i++){
|
| + struct Cte *pCte = &pWith->a[i];
|
| + sqlite3ExprListDelete(db, pCte->pCols);
|
| + sqlite3SelectDelete(db, pCte->pSelect);
|
| + sqlite3DbFree(db, pCte->zName);
|
| + }
|
| + sqlite3DbFree(db, pWith);
|
| + }
|
| +}
|
| +#endif /* !defined(SQLITE_OMIT_CTE) */
|
| +
|
| +/************** End of build.c ***********************************************/
|
| +/************** Begin file callback.c ****************************************/
|
| +/*
|
| +** 2005 May 23
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +**
|
| +** This file contains functions used to access the internal hash tables
|
| +** of user defined functions and collation sequences.
|
| +*/
|
| +
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +/*
|
| +** Invoke the 'collation needed' callback to request a collation sequence
|
| +** in the encoding enc of name zName, length nName.
|
| +*/
|
| +static void callCollNeeded(sqlite3 *db, int enc, const char *zName){
|
| + assert( !db->xCollNeeded || !db->xCollNeeded16 );
|
| + if( db->xCollNeeded ){
|
| + char *zExternal = sqlite3DbStrDup(db, zName);
|
| + if( !zExternal ) return;
|
| + db->xCollNeeded(db->pCollNeededArg, db, enc, zExternal);
|
| + sqlite3DbFree(db, zExternal);
|
| + }
|
| +#ifndef SQLITE_OMIT_UTF16
|
| + if( db->xCollNeeded16 ){
|
| + char const *zExternal;
|
| + sqlite3_value *pTmp = sqlite3ValueNew(db);
|
| + sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC);
|
| + zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
|
| + if( zExternal ){
|
| + db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal);
|
| + }
|
| + sqlite3ValueFree(pTmp);
|
| + }
|
| +#endif
|
| +}
|
| +
|
| +/*
|
| +** This routine is called if the collation factory fails to deliver a
|
| +** collation function in the best encoding but there may be other versions
|
| +** of this collation function (for other text encodings) available. Use one
|
| +** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if
|
| +** possible.
|
| +*/
|
| +static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
|
| + CollSeq *pColl2;
|
| + char *z = pColl->zName;
|
| + int i;
|
| + static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 };
|
| + for(i=0; i<3; i++){
|
| + pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, 0);
|
| + if( pColl2->xCmp!=0 ){
|
| + memcpy(pColl, pColl2, sizeof(CollSeq));
|
| + pColl->xDel = 0; /* Do not copy the destructor */
|
| + return SQLITE_OK;
|
| + }
|
| + }
|
| + return SQLITE_ERROR;
|
| +}
|
| +
|
| +/*
|
| +** This function is responsible for invoking the collation factory callback
|
| +** or substituting a collation sequence of a different encoding when the
|
| +** requested collation sequence is not available in the desired encoding.
|
| +**
|
| +** If it is not NULL, then pColl must point to the database native encoding
|
| +** collation sequence with name zName, length nName.
|
| +**
|
| +** The return value is either the collation sequence to be used in database
|
| +** db for collation type name zName, length nName, or NULL, if no collation
|
| +** sequence can be found. If no collation is found, leave an error message.
|
| +**
|
| +** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
|
| +*/
|
| +SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
|
| + Parse *pParse, /* Parsing context */
|
| + u8 enc, /* The desired encoding for the collating sequence */
|
| + CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
|
| + const char *zName /* Collating sequence name */
|
| +){
|
| + CollSeq *p;
|
| + sqlite3 *db = pParse->db;
|
| +
|
| + p = pColl;
|
| + if( !p ){
|
| + p = sqlite3FindCollSeq(db, enc, zName, 0);
|
| + }
|
| + if( !p || !p->xCmp ){
|
| + /* No collation sequence of this type for this encoding is registered.
|
| + ** Call the collation factory to see if it can supply us with one.
|
| + */
|
| + callCollNeeded(db, enc, zName);
|
| + p = sqlite3FindCollSeq(db, enc, zName, 0);
|
| + }
|
| + if( p && !p->xCmp && synthCollSeq(db, p) ){
|
| + p = 0;
|
| + }
|
| + assert( !p || p->xCmp );
|
| + if( p==0 ){
|
| + sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
|
| + }
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** This routine is called on a collation sequence before it is used to
|
| +** check that it is defined. An undefined collation sequence exists when
|
| +** a database is loaded that contains references to collation sequences
|
| +** that have not been defined by sqlite3_create_collation() etc.
|
| +**
|
| +** If required, this routine calls the 'collation needed' callback to
|
| +** request a definition of the collating sequence. If this doesn't work,
|
| +** an equivalent collating sequence that uses a text encoding different
|
| +** from the main database is substituted, if one is available.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
|
| + if( pColl ){
|
| + const char *zName = pColl->zName;
|
| + sqlite3 *db = pParse->db;
|
| + CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
|
| + if( !p ){
|
| + return SQLITE_ERROR;
|
| + }
|
| + assert( p==pColl );
|
| + }
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +
|
| +
|
| +/*
|
| +** Locate and return an entry from the db.aCollSeq hash table. If the entry
|
| +** specified by zName and nName is not found and parameter 'create' is
|
| +** true, then create a new entry. Otherwise return NULL.
|
| +**
|
| +** Each pointer stored in the sqlite3.aCollSeq hash table contains an
|
| +** array of three CollSeq structures. The first is the collation sequence
|
| +** preferred for UTF-8, the second UTF-16le, and the third UTF-16be.
|
| +**
|
| +** Stored immediately after the three collation sequences is a copy of
|
| +** the collation sequence name. A pointer to this string is stored in
|
| +** each collation sequence structure.
|
| +*/
|
| +static CollSeq *findCollSeqEntry(
|
| + sqlite3 *db, /* Database connection */
|
| + const char *zName, /* Name of the collating sequence */
|
| + int create /* Create a new entry if true */
|
| +){
|
| + CollSeq *pColl;
|
| + pColl = sqlite3HashFind(&db->aCollSeq, zName);
|
| +
|
| + if( 0==pColl && create ){
|
| + int nName = sqlite3Strlen30(zName);
|
| + pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1);
|
| + if( pColl ){
|
| + CollSeq *pDel = 0;
|
| + pColl[0].zName = (char*)&pColl[3];
|
| + pColl[0].enc = SQLITE_UTF8;
|
| + pColl[1].zName = (char*)&pColl[3];
|
| + pColl[1].enc = SQLITE_UTF16LE;
|
| + pColl[2].zName = (char*)&pColl[3];
|
| + pColl[2].enc = SQLITE_UTF16BE;
|
| + memcpy(pColl[0].zName, zName, nName);
|
| + pColl[0].zName[nName] = 0;
|
| + pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
|
| +
|
| + /* If a malloc() failure occurred in sqlite3HashInsert(), it will
|
| + ** return the pColl pointer to be deleted (because it wasn't added
|
| + ** to the hash table).
|
| + */
|
| + assert( pDel==0 || pDel==pColl );
|
| + if( pDel!=0 ){
|
| + db->mallocFailed = 1;
|
| + sqlite3DbFree(db, pDel);
|
| + pColl = 0;
|
| + }
|
| + }
|
| + }
|
| + return pColl;
|
| +}
|
| +
|
| +/*
|
| +** Parameter zName points to a UTF-8 encoded string nName bytes long.
|
| +** Return the CollSeq* pointer for the collation sequence named zName
|
| +** for the encoding 'enc' from the database 'db'.
|
| +**
|
| +** If the entry specified is not found and 'create' is true, then create a
|
| +** new entry. Otherwise return NULL.
|
| +**
|
| +** A separate function sqlite3LocateCollSeq() is a wrapper around
|
| +** this routine. sqlite3LocateCollSeq() invokes the collation factory
|
| +** if necessary and generates an error message if the collating sequence
|
| +** cannot be found.
|
| +**
|
| +** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq()
|
| +*/
|
| +SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
|
| + sqlite3 *db,
|
| + u8 enc,
|
| + const char *zName,
|
| + int create
|
| +){
|
| + CollSeq *pColl;
|
| + if( zName ){
|
| + pColl = findCollSeqEntry(db, zName, create);
|
| + }else{
|
| + pColl = db->pDfltColl;
|
| + }
|
| + assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
| + assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
|
| + if( pColl ) pColl += enc-1;
|
| + return pColl;
|
| +}
|
| +
|
| +/* During the search for the best function definition, this procedure
|
| +** is called to test how well the function passed as the first argument
|
| +** matches the request for a function with nArg arguments in a system
|
| +** that uses encoding enc. The value returned indicates how well the
|
| +** request is matched. A higher value indicates a better match.
|
| +**
|
| +** If nArg is -1 that means to only return a match (non-zero) if p->nArg
|
| +** is also -1. In other words, we are searching for a function that
|
| +** takes a variable number of arguments.
|
| +**
|
| +** If nArg is -2 that means that we are searching for any function
|
| +** regardless of the number of arguments it uses, so return a positive
|
| +** match score for any
|
| +**
|
| +** The returned value is always between 0 and 6, as follows:
|
| +**
|
| +** 0: Not a match.
|
| +** 1: UTF8/16 conversion required and function takes any number of arguments.
|
| +** 2: UTF16 byte order change required and function takes any number of args.
|
| +** 3: encoding matches and function takes any number of arguments
|
| +** 4: UTF8/16 conversion required - argument count matches exactly
|
| +** 5: UTF16 byte order conversion required - argument count matches exactly
|
| +** 6: Perfect match: encoding and argument count match exactly.
|
| +**
|
| +** If nArg==(-2) then any function with a non-null xStep or xFunc is
|
| +** a perfect match and any function with both xStep and xFunc NULL is
|
| +** a non-match.
|
| +*/
|
| +#define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */
|
| +static int matchQuality(
|
| + FuncDef *p, /* The function we are evaluating for match quality */
|
| + int nArg, /* Desired number of arguments. (-1)==any */
|
| + u8 enc /* Desired text encoding */
|
| +){
|
| + int match;
|
| +
|
| + /* nArg of -2 is a special case */
|
| + if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH;
|
| +
|
| + /* Wrong number of arguments means "no match" */
|
| + if( p->nArg!=nArg && p->nArg>=0 ) return 0;
|
| +
|
| + /* Give a better score to a function with a specific number of arguments
|
| + ** than to function that accepts any number of arguments. */
|
| + if( p->nArg==nArg ){
|
| + match = 4;
|
| + }else{
|
| + match = 1;
|
| + }
|
| +
|
| + /* Bonus points if the text encoding matches */
|
| + if( enc==(p->funcFlags & SQLITE_FUNC_ENCMASK) ){
|
| + match += 2; /* Exact encoding match */
|
| + }else if( (enc & p->funcFlags & 2)!=0 ){
|
| + match += 1; /* Both are UTF16, but with different byte orders */
|
| + }
|
| +
|
| + return match;
|
| +}
|
| +
|
| +/*
|
| +** Search a FuncDefHash for a function with the given name. Return
|
| +** a pointer to the matching FuncDef if found, or 0 if there is no match.
|
| +*/
|
| +static FuncDef *functionSearch(
|
| + FuncDefHash *pHash, /* Hash table to search */
|
| + int h, /* Hash of the name */
|
| + const char *zFunc, /* Name of function */
|
| + int nFunc /* Number of bytes in zFunc */
|
| +){
|
| + FuncDef *p;
|
| + for(p=pHash->a[h]; p; p=p->pHash){
|
| + if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
|
| + return p;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** Insert a new FuncDef into a FuncDefHash hash table.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3FuncDefInsert(
|
| + FuncDefHash *pHash, /* The hash table into which to insert */
|
| + FuncDef *pDef /* The function definition to insert */
|
| +){
|
| + FuncDef *pOther;
|
| + int nName = sqlite3Strlen30(pDef->zName);
|
| + u8 c1 = (u8)pDef->zName[0];
|
| + int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
|
| + pOther = functionSearch(pHash, h, pDef->zName, nName);
|
| + if( pOther ){
|
| + assert( pOther!=pDef && pOther->pNext!=pDef );
|
| + pDef->pNext = pOther->pNext;
|
| + pOther->pNext = pDef;
|
| + }else{
|
| + pDef->pNext = 0;
|
| + pDef->pHash = pHash->a[h];
|
| + pHash->a[h] = pDef;
|
| + }
|
| +}
|
| +
|
| +
|
| +
|
| +/*
|
| +** Locate a user function given a name, a number of arguments and a flag
|
| +** indicating whether the function prefers UTF-16 over UTF-8. Return a
|
| +** pointer to the FuncDef structure that defines that function, or return
|
| +** NULL if the function does not exist.
|
| +**
|
| +** If the createFlag argument is true, then a new (blank) FuncDef
|
| +** structure is created and liked into the "db" structure if a
|
| +** no matching function previously existed.
|
| +**
|
| +** If nArg is -2, then the first valid function found is returned. A
|
| +** function is valid if either xFunc or xStep is non-zero. The nArg==(-2)
|
| +** case is used to see if zName is a valid function name for some number
|
| +** of arguments. If nArg is -2, then createFlag must be 0.
|
| +**
|
| +** If createFlag is false, then a function with the required name and
|
| +** number of arguments may be returned even if the eTextRep flag does not
|
| +** match that requested.
|
| +*/
|
| +SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
|
| + sqlite3 *db, /* An open database */
|
| + const char *zName, /* Name of the function. Not null-terminated */
|
| + int nName, /* Number of characters in the name */
|
| + int nArg, /* Number of arguments. -1 means any number */
|
| + u8 enc, /* Preferred text encoding */
|
| + u8 createFlag /* Create new entry if true and does not otherwise exist */
|
| +){
|
| + FuncDef *p; /* Iterator variable */
|
| + FuncDef *pBest = 0; /* Best match found so far */
|
| + int bestScore = 0; /* Score of best match */
|
| + int h; /* Hash value */
|
| +
|
| + assert( nArg>=(-2) );
|
| + assert( nArg>=(-1) || createFlag==0 );
|
| + h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
|
| +
|
| + /* First search for a match amongst the application-defined functions.
|
| + */
|
| + p = functionSearch(&db->aFunc, h, zName, nName);
|
| + while( p ){
|
| + int score = matchQuality(p, nArg, enc);
|
| + if( score>bestScore ){
|
| + pBest = p;
|
| + bestScore = score;
|
| + }
|
| + p = p->pNext;
|
| + }
|
| +
|
| + /* If no match is found, search the built-in functions.
|
| + **
|
| + ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
|
| + ** functions even if a prior app-defined function was found. And give
|
| + ** priority to built-in functions.
|
| + **
|
| + ** Except, if createFlag is true, that means that we are trying to
|
| + ** install a new function. Whatever FuncDef structure is returned it will
|
| + ** have fields overwritten with new information appropriate for the
|
| + ** new function. But the FuncDefs for built-in functions are read-only.
|
| + ** So we must not search for built-ins when creating a new function.
|
| + */
|
| + if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
|
| + FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
|
| + bestScore = 0;
|
| + p = functionSearch(pHash, h, zName, nName);
|
| + while( p ){
|
| + int score = matchQuality(p, nArg, enc);
|
| + if( score>bestScore ){
|
| + pBest = p;
|
| + bestScore = score;
|
| + }
|
| + p = p->pNext;
|
| + }
|
| + }
|
| +
|
| + /* If the createFlag parameter is true and the search did not reveal an
|
| + ** exact match for the name, number of arguments and encoding, then add a
|
| + ** new entry to the hash table and return it.
|
| + */
|
| + if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
|
| + (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
|
| + pBest->zName = (char *)&pBest[1];
|
| + pBest->nArg = (u16)nArg;
|
| + pBest->funcFlags = enc;
|
| + memcpy(pBest->zName, zName, nName);
|
| + pBest->zName[nName] = 0;
|
| + sqlite3FuncDefInsert(&db->aFunc, pBest);
|
| + }
|
| +
|
| + if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
|
| + return pBest;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** Free all resources held by the schema structure. The void* argument points
|
| +** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
|
| +** pointer itself, it just cleans up subsidiary resources (i.e. the contents
|
| +** of the schema hash tables).
|
| +**
|
| +** The Schema.cache_size variable is not cleared.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
|
| + Hash temp1;
|
| + Hash temp2;
|
| + HashElem *pElem;
|
| + Schema *pSchema = (Schema *)p;
|
| +
|
| + temp1 = pSchema->tblHash;
|
| + temp2 = pSchema->trigHash;
|
| + sqlite3HashInit(&pSchema->trigHash);
|
| + sqlite3HashClear(&pSchema->idxHash);
|
| + for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
|
| + sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem));
|
| + }
|
| + sqlite3HashClear(&temp2);
|
| + sqlite3HashInit(&pSchema->tblHash);
|
| + for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
| + Table *pTab = sqliteHashData(pElem);
|
| + sqlite3DeleteTable(0, pTab);
|
| + }
|
| + sqlite3HashClear(&temp1);
|
| + sqlite3HashClear(&pSchema->fkeyHash);
|
| + pSchema->pSeqTab = 0;
|
| + if( pSchema->schemaFlags & DB_SchemaLoaded ){
|
| + pSchema->iGeneration++;
|
| + pSchema->schemaFlags &= ~DB_SchemaLoaded;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Find and return the schema associated with a BTree. Create
|
| +** a new one if necessary.
|
| +*/
|
| +SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
|
| + Schema * p;
|
| + if( pBt ){
|
| + p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
|
| + }else{
|
| + p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
|
| + }
|
| + if( !p ){
|
| + db->mallocFailed = 1;
|
| + }else if ( 0==p->file_format ){
|
| + sqlite3HashInit(&p->tblHash);
|
| + sqlite3HashInit(&p->idxHash);
|
| + sqlite3HashInit(&p->trigHash);
|
| + sqlite3HashInit(&p->fkeyHash);
|
| + p->enc = SQLITE_UTF8;
|
| + }
|
| + return p;
|
| +}
|
| +
|
| +/************** End of callback.c ********************************************/
|
| +/************** Begin file delete.c ******************************************/
|
| +/*
|
| +** 2001 September 15
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains C code routines that are called by the parser
|
| +** in order to generate code for DELETE FROM statements.
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +/*
|
| +** While a SrcList can in general represent multiple tables and subqueries
|
| +** (as in the FROM clause of a SELECT statement) in this case it contains
|
| +** the name of a single table, as one might find in an INSERT, DELETE,
|
| +** or UPDATE statement. Look up that table in the symbol table and
|
| +** return a pointer. Set an error message and return NULL if the table
|
| +** name is not found or if any other error occurs.
|
| +**
|
| +** The following fields are initialized appropriate in pSrc:
|
| +**
|
| +** pSrc->a[0].pTab Pointer to the Table object
|
| +** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one
|
| +**
|
| +*/
|
| +SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
| + struct SrcList_item *pItem = pSrc->a;
|
| + Table *pTab;
|
| + assert( pItem && pSrc->nSrc==1 );
|
| + pTab = sqlite3LocateTableItem(pParse, 0, pItem);
|
| + sqlite3DeleteTable(pParse->db, pItem->pTab);
|
| + pItem->pTab = pTab;
|
| + if( pTab ){
|
| + pTab->nRef++;
|
| + }
|
| + if( sqlite3IndexedByLookup(pParse, pItem) ){
|
| + pTab = 0;
|
| + }
|
| + return pTab;
|
| +}
|
| +
|
| +/*
|
| +** Check to make sure the given table is writable. If it is not
|
| +** writable, generate an error message and return 1. If it is
|
| +** writable return 0;
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
| + /* A table is not writable under the following circumstances:
|
| + **
|
| + ** 1) It is a virtual table and no implementation of the xUpdate method
|
| + ** has been provided, or
|
| + ** 2) It is a system table (i.e. sqlite_master), this call is not
|
| + ** part of a nested parse and writable_schema pragma has not
|
| + ** been specified.
|
| + **
|
| + ** In either case leave an error message in pParse and return non-zero.
|
| + */
|
| + if( ( IsVirtual(pTab)
|
| + && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 )
|
| + || ( (pTab->tabFlags & TF_Readonly)!=0
|
| + && (pParse->db->flags & SQLITE_WriteSchema)==0
|
| + && pParse->nested==0 )
|
| + ){
|
| + sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
|
| + return 1;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_VIEW
|
| + if( !viewOk && pTab->pSelect ){
|
| + sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
|
| + return 1;
|
| + }
|
| +#endif
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
| +/*
|
| +** Evaluate a view and store its result in an ephemeral table. The
|
| +** pWhere argument is an optional WHERE clause that restricts the
|
| +** set of rows in the view that are to be added to the ephemeral table.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3MaterializeView(
|
| + Parse *pParse, /* Parsing context */
|
| + Table *pView, /* View definition */
|
| + Expr *pWhere, /* Optional WHERE clause to be added */
|
| + int iCur /* Cursor number for ephemeral table */
|
| +){
|
| + SelectDest dest;
|
| + Select *pSel;
|
| + SrcList *pFrom;
|
| + sqlite3 *db = pParse->db;
|
| + int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
|
| + pWhere = sqlite3ExprDup(db, pWhere, 0);
|
| + pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
|
| + if( pFrom ){
|
| + assert( pFrom->nSrc==1 );
|
| + pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
| + pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
|
| + assert( pFrom->a[0].pOn==0 );
|
| + assert( pFrom->a[0].pUsing==0 );
|
| + }
|
| + pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0,
|
| + SF_IncludeHidden, 0, 0);
|
| + sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
|
| + sqlite3Select(pParse, pSel, &dest);
|
| + sqlite3SelectDelete(db, pSel);
|
| +}
|
| +#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
|
| +
|
| +#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
|
| +/*
|
| +** Generate an expression tree to implement the WHERE, ORDER BY,
|
| +** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
|
| +**
|
| +** DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
|
| +** \__________________________/
|
| +** pLimitWhere (pInClause)
|
| +*/
|
| +SQLITE_PRIVATE Expr *sqlite3LimitWhere(
|
| + Parse *pParse, /* The parser context */
|
| + SrcList *pSrc, /* the FROM clause -- which tables to scan */
|
| + Expr *pWhere, /* The WHERE clause. May be null */
|
| + ExprList *pOrderBy, /* The ORDER BY clause. May be null */
|
| + Expr *pLimit, /* The LIMIT clause. May be null */
|
| + Expr *pOffset, /* The OFFSET clause. May be null */
|
| + char *zStmtType /* Either DELETE or UPDATE. For err msgs. */
|
| +){
|
| + Expr *pWhereRowid = NULL; /* WHERE rowid .. */
|
| + Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
|
| + Expr *pSelectRowid = NULL; /* SELECT rowid ... */
|
| + ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
|
| + SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
|
| + Select *pSelect = NULL; /* Complete SELECT tree */
|
| +
|
| + /* Check that there isn't an ORDER BY without a LIMIT clause.
|
| + */
|
| + if( pOrderBy && (pLimit == 0) ) {
|
| + sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
|
| + goto limit_where_cleanup_2;
|
| + }
|
| +
|
| + /* We only need to generate a select expression if there
|
| + ** is a limit/offset term to enforce.
|
| + */
|
| + if( pLimit == 0 ) {
|
| + /* if pLimit is null, pOffset will always be null as well. */
|
| + assert( pOffset == 0 );
|
| + return pWhere;
|
| + }
|
| +
|
| + /* Generate a select expression tree to enforce the limit/offset
|
| + ** term for the DELETE or UPDATE statement. For example:
|
| + ** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
|
| + ** becomes:
|
| + ** DELETE FROM table_a WHERE rowid IN (
|
| + ** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
|
| + ** );
|
| + */
|
| +
|
| + pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
|
| + if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
|
| + pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
|
| + if( pEList == 0 ) goto limit_where_cleanup_2;
|
| +
|
| + /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
| + ** and the SELECT subtree. */
|
| + pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
| + if( pSelectSrc == 0 ) {
|
| + sqlite3ExprListDelete(pParse->db, pEList);
|
| + goto limit_where_cleanup_2;
|
| + }
|
| +
|
| + /* generate the SELECT expression tree. */
|
| + pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,
|
| + pOrderBy,0,pLimit,pOffset);
|
| + if( pSelect == 0 ) return 0;
|
| +
|
| + /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
|
| + pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
|
| + if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
|
| + pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
|
| + if( pInClause == 0 ) goto limit_where_cleanup_1;
|
| +
|
| + pInClause->x.pSelect = pSelect;
|
| + pInClause->flags |= EP_xIsSelect;
|
| + sqlite3ExprSetHeightAndFlags(pParse, pInClause);
|
| + return pInClause;
|
| +
|
| + /* something went wrong. clean up anything allocated. */
|
| +limit_where_cleanup_1:
|
| + sqlite3SelectDelete(pParse->db, pSelect);
|
| + return 0;
|
| +
|
| +limit_where_cleanup_2:
|
| + sqlite3ExprDelete(pParse->db, pWhere);
|
| + sqlite3ExprListDelete(pParse->db, pOrderBy);
|
| + sqlite3ExprDelete(pParse->db, pLimit);
|
| + sqlite3ExprDelete(pParse->db, pOffset);
|
| + return 0;
|
| +}
|
| +#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */
|
| + /* && !defined(SQLITE_OMIT_SUBQUERY) */
|
| +
|
| +/*
|
| +** Generate code for a DELETE FROM statement.
|
| +**
|
| +** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
|
| +** \________/ \________________/
|
| +** pTabList pWhere
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3DeleteFrom(
|
| + Parse *pParse, /* The parser context */
|
| + SrcList *pTabList, /* The table from which we should delete things */
|
| + Expr *pWhere /* The WHERE clause. May be null */
|
| +){
|
| + Vdbe *v; /* The virtual database engine */
|
| + Table *pTab; /* The table from which records will be deleted */
|
| + const char *zDb; /* Name of database holding pTab */
|
| + int i; /* Loop counter */
|
| + WhereInfo *pWInfo; /* Information about the WHERE clause */
|
| + Index *pIdx; /* For looping over indices of the table */
|
| + int iTabCur; /* Cursor number for the table */
|
| + int iDataCur = 0; /* VDBE cursor for the canonical data source */
|
| + int iIdxCur = 0; /* Cursor number of the first index */
|
| + int nIdx; /* Number of indices */
|
| + sqlite3 *db; /* Main database structure */
|
| + AuthContext sContext; /* Authorization context */
|
| + NameContext sNC; /* Name context to resolve expressions in */
|
| + int iDb; /* Database number */
|
| + int memCnt = -1; /* Memory cell used for change counting */
|
| + int rcauth; /* Value returned by authorization callback */
|
| + int eOnePass; /* ONEPASS_OFF or _SINGLE or _MULTI */
|
| + int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
|
| + u8 *aToOpen = 0; /* Open cursor iTabCur+j if aToOpen[j] is true */
|
| + Index *pPk; /* The PRIMARY KEY index on the table */
|
| + int iPk = 0; /* First of nPk registers holding PRIMARY KEY value */
|
| + i16 nPk = 1; /* Number of columns in the PRIMARY KEY */
|
| + int iKey; /* Memory cell holding key of row to be deleted */
|
| + i16 nKey; /* Number of memory cells in the row key */
|
| + int iEphCur = 0; /* Ephemeral table holding all primary key values */
|
| + int iRowSet = 0; /* Register for rowset of rows to delete */
|
| + int addrBypass = 0; /* Address of jump over the delete logic */
|
| + int addrLoop = 0; /* Top of the delete loop */
|
| + int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
|
| +
|
| +#ifndef SQLITE_OMIT_TRIGGER
|
| + int isView; /* True if attempting to delete from a view */
|
| + Trigger *pTrigger; /* List of table triggers, if required */
|
| + int bComplex; /* True if there are either triggers or FKs */
|
| +#endif
|
| +
|
| + memset(&sContext, 0, sizeof(sContext));
|
| + db = pParse->db;
|
| + if( pParse->nErr || db->mallocFailed ){
|
| + goto delete_from_cleanup;
|
| + }
|
| + assert( pTabList->nSrc==1 );
|
| +
|
| + /* Locate the table which we want to delete. This table has to be
|
| + ** put in an SrcList structure because some of the subroutines we
|
| + ** will be calling are designed to work with multiple tables and expect
|
| + ** an SrcList* parameter instead of just a Table* parameter.
|
| + */
|
| + pTab = sqlite3SrcListLookup(pParse, pTabList);
|
| + if( pTab==0 ) goto delete_from_cleanup;
|
| +
|
| + /* Figure out if we have any triggers and if the table being
|
| + ** deleted from is a view
|
| + */
|
| +#ifndef SQLITE_OMIT_TRIGGER
|
| + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
| + isView = pTab->pSelect!=0;
|
| + bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
|
| +#else
|
| +# define pTrigger 0
|
| +# define isView 0
|
| +# define bComplex 0
|
| +#endif
|
| +#ifdef SQLITE_OMIT_VIEW
|
| +# undef isView
|
| +# define isView 0
|
| +#endif
|
| +
|
| + /* If pTab is really a view, make sure it has been initialized.
|
| + */
|
| + if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
| + goto delete_from_cleanup;
|
| + }
|
| +
|
| + if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
|
| + goto delete_from_cleanup;
|
| + }
|
| + iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| + assert( iDb<db->nDb );
|
| + zDb = db->aDb[iDb].zName;
|
| + rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
|
| + assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
|
| + if( rcauth==SQLITE_DENY ){
|
| + goto delete_from_cleanup;
|
| + }
|
| + assert(!isView || pTrigger);
|
| +
|
| + /* Assign cursor numbers to the table and all its indices.
|
| + */
|
| + assert( pTabList->nSrc==1 );
|
| + iTabCur = pTabList->a[0].iCursor = pParse->nTab++;
|
| + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
|
| + pParse->nTab++;
|
| + }
|
| +
|
| + /* Start the view context
|
| + */
|
| + if( isView ){
|
| + sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
|
| + }
|
| +
|
| + /* Begin generating code.
|
| + */
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v==0 ){
|
| + goto delete_from_cleanup;
|
| + }
|
| + if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
| + sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| +
|
| + /* If we are trying to delete from a view, realize that view into
|
| + ** an ephemeral table.
|
| + */
|
| +#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
| + if( isView ){
|
| + sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
|
| + iDataCur = iIdxCur = iTabCur;
|
| + }
|
| +#endif
|
| +
|
| + /* Resolve the column names in the WHERE clause.
|
| + */
|
| + memset(&sNC, 0, sizeof(sNC));
|
| + sNC.pParse = pParse;
|
| + sNC.pSrcList = pTabList;
|
| + if( sqlite3ResolveExprNames(&sNC, pWhere) ){
|
| + goto delete_from_cleanup;
|
| + }
|
| +
|
| + /* Initialize the counter of the number of rows deleted, if
|
| + ** we are counting rows.
|
| + */
|
| + if( db->flags & SQLITE_CountRows ){
|
| + memCnt = ++pParse->nMem;
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
| + /* Special case: A DELETE without a WHERE clause deletes everything.
|
| + ** It is easier just to erase the whole table. Prior to version 3.6.5,
|
| + ** this optimization caused the row change count (the value returned by
|
| + ** API function sqlite3_count_changes) to be set incorrectly. */
|
| + if( rcauth==SQLITE_OK
|
| + && pWhere==0
|
| + && !bComplex
|
| + && !IsVirtual(pTab)
|
| + ){
|
| + assert( !isView );
|
| + sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
|
| + if( HasRowid(pTab) ){
|
| + sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
|
| + pTab->zName, P4_STATIC);
|
| + }
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + assert( pIdx->pSchema==pTab->pSchema );
|
| + sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
|
| + }
|
| + }else
|
| +#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
|
| + {
|
| + u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
|
| + wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
|
| + if( HasRowid(pTab) ){
|
| + /* For a rowid table, initialize the RowSet to an empty set */
|
| + pPk = 0;
|
| + nPk = 1;
|
| + iRowSet = ++pParse->nMem;
|
| + sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
|
| + }else{
|
| + /* For a WITHOUT ROWID table, create an ephemeral table used to
|
| + ** hold all primary keys for rows to be deleted. */
|
| + pPk = sqlite3PrimaryKeyIndex(pTab);
|
| + assert( pPk!=0 );
|
| + nPk = pPk->nKeyCol;
|
| + iPk = pParse->nMem+1;
|
| + pParse->nMem += nPk;
|
| + iEphCur = pParse->nTab++;
|
| + addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk);
|
| + sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
| + }
|
| +
|
| + /* Construct a query to find the rowid or primary key for every row
|
| + ** to be deleted, based on the WHERE clause. Set variable eOnePass
|
| + ** to indicate the strategy used to implement this delete:
|
| + **
|
| + ** ONEPASS_OFF: Two-pass approach - use a FIFO for rowids/PK values.
|
| + ** ONEPASS_SINGLE: One-pass approach - at most one row deleted.
|
| + ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted.
|
| + */
|
| + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1);
|
| + if( pWInfo==0 ) goto delete_from_cleanup;
|
| + eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
| + assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
|
| + assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
|
| +
|
| + /* Keep track of the number of rows to be deleted */
|
| + if( db->flags & SQLITE_CountRows ){
|
| + sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
|
| + }
|
| +
|
| + /* Extract the rowid or primary key for the current row */
|
| + if( pPk ){
|
| + for(i=0; i<nPk; i++){
|
| + assert( pPk->aiColumn[i]>=0 );
|
| + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
|
| + pPk->aiColumn[i], iPk+i);
|
| + }
|
| + iKey = iPk;
|
| + }else{
|
| + iKey = pParse->nMem + 1;
|
| + iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0);
|
| + if( iKey>pParse->nMem ) pParse->nMem = iKey;
|
| + }
|
| +
|
| + if( eOnePass!=ONEPASS_OFF ){
|
| + /* For ONEPASS, no need to store the rowid/primary-key. There is only
|
| + ** one, so just keep it in its register(s) and fall through to the
|
| + ** delete code. */
|
| + nKey = nPk; /* OP_Found will use an unpacked key */
|
| + aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
|
| + if( aToOpen==0 ){
|
| + sqlite3WhereEnd(pWInfo);
|
| + goto delete_from_cleanup;
|
| + }
|
| + memset(aToOpen, 1, nIdx+1);
|
| + aToOpen[nIdx+1] = 0;
|
| + if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
|
| + if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
|
| + if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen);
|
| + }else{
|
| + if( pPk ){
|
| + /* Add the PK key for this row to the temporary table */
|
| + iKey = ++pParse->nMem;
|
| + nKey = 0; /* Zero tells OP_Found to use a composite key */
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
|
| + sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
|
| + }else{
|
| + /* Add the rowid of the row to be deleted to the RowSet */
|
| + nKey = 1; /* OP_Seek always uses a single rowid */
|
| + sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
|
| + }
|
| + }
|
| +
|
| + /* If this DELETE cannot use the ONEPASS strategy, this is the
|
| + ** end of the WHERE loop */
|
| + if( eOnePass!=ONEPASS_OFF ){
|
| + addrBypass = sqlite3VdbeMakeLabel(v);
|
| + }else{
|
| + sqlite3WhereEnd(pWInfo);
|
| + }
|
| +
|
| + /* Unless this is a view, open cursors for the table we are
|
| + ** deleting from and all its indices. If this is a view, then the
|
| + ** only effect this statement has is to fire the INSTEAD OF
|
| + ** triggers.
|
| + */
|
| + if( !isView ){
|
| + int iAddrOnce = 0;
|
| + u8 p5 = (eOnePass==ONEPASS_OFF ? 0 : OPFLAG_FORDELETE);
|
| + if( eOnePass==ONEPASS_MULTI ){
|
| + iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
| + }
|
| + testcase( IsVirtual(pTab) );
|
| + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, p5, iTabCur,
|
| + aToOpen, &iDataCur, &iIdxCur);
|
| + assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
|
| + assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
|
| + if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
|
| + }
|
| +
|
| + /* Set up a loop over the rowids/primary-keys that were found in the
|
| + ** where-clause loop above.
|
| + */
|
| + if( eOnePass!=ONEPASS_OFF ){
|
| + assert( nKey==nPk ); /* OP_Found will use an unpacked key */
|
| + if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){
|
| + assert( pPk!=0 || pTab->pSelect!=0 );
|
| + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
|
| + VdbeCoverage(v);
|
| + }
|
| + }else if( pPk ){
|
| + addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
|
| + assert( nKey==0 ); /* OP_Found will use a composite key */
|
| + }else{
|
| + addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
|
| + VdbeCoverage(v);
|
| + assert( nKey==1 );
|
| + }
|
| +
|
| + /* Delete the row */
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( IsVirtual(pTab) ){
|
| + const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
| + sqlite3VtabMakeWritable(pParse, pTab);
|
| + sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
|
| + sqlite3VdbeChangeP5(v, OE_Abort);
|
| + assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
|
| + sqlite3MayAbort(pParse);
|
| + if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){
|
| + pParse->isMultiWrite = 0;
|
| + }
|
| + }else
|
| +#endif
|
| + {
|
| + int count = (pParse->nested==0); /* True to count changes */
|
| + int iIdxNoSeek = -1;
|
| + if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){
|
| + iIdxNoSeek = aiCurOnePass[1];
|
| + }
|
| + sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
| + iKey, nKey, count, OE_Default, eOnePass, iIdxNoSeek);
|
| + }
|
| +
|
| + /* End of the loop over all rowids/primary-keys. */
|
| + if( eOnePass!=ONEPASS_OFF ){
|
| + sqlite3VdbeResolveLabel(v, addrBypass);
|
| + sqlite3WhereEnd(pWInfo);
|
| + }else if( pPk ){
|
| + sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addrLoop);
|
| + }else{
|
| + sqlite3VdbeGoto(v, addrLoop);
|
| + sqlite3VdbeJumpHere(v, addrLoop);
|
| + }
|
| +
|
| + /* Close the cursors open on the table and its indexes. */
|
| + if( !isView && !IsVirtual(pTab) ){
|
| + if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
|
| + for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
| + sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
|
| + }
|
| + }
|
| + } /* End non-truncate path */
|
| +
|
| + /* Update the sqlite_sequence table by storing the content of the
|
| + ** maximum rowid counter values recorded while inserting into
|
| + ** autoincrement tables.
|
| + */
|
| + if( pParse->nested==0 && pParse->pTriggerTab==0 ){
|
| + sqlite3AutoincrementEnd(pParse);
|
| + }
|
| +
|
| + /* Return the number of rows that were deleted. If this routine is
|
| + ** generating code because of a call to sqlite3NestedParse(), do not
|
| + ** invoke the callback function.
|
| + */
|
| + if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
|
| + sqlite3VdbeSetNumCols(v, 1);
|
| + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
|
| + }
|
| +
|
| +delete_from_cleanup:
|
| + sqlite3AuthContextPop(&sContext);
|
| + sqlite3SrcListDelete(db, pTabList);
|
| + sqlite3ExprDelete(db, pWhere);
|
| + sqlite3DbFree(db, aToOpen);
|
| + return;
|
| +}
|
| +/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
| +** they may interfere with compilation of other functions in this file
|
| +** (or in another file, if this file becomes part of the amalgamation). */
|
| +#ifdef isView
|
| + #undef isView
|
| +#endif
|
| +#ifdef pTrigger
|
| + #undef pTrigger
|
| +#endif
|
| +
|
| +/*
|
| +** This routine generates VDBE code that causes a single row of a
|
| +** single table to be deleted. Both the original table entry and
|
| +** all indices are removed.
|
| +**
|
| +** Preconditions:
|
| +**
|
| +** 1. iDataCur is an open cursor on the btree that is the canonical data
|
| +** store for the table. (This will be either the table itself,
|
| +** in the case of a rowid table, or the PRIMARY KEY index in the case
|
| +** of a WITHOUT ROWID table.)
|
| +**
|
| +** 2. Read/write cursors for all indices of pTab must be open as
|
| +** cursor number iIdxCur+i for the i-th index.
|
| +**
|
| +** 3. The primary key for the row to be deleted must be stored in a
|
| +** sequence of nPk memory cells starting at iPk. If nPk==0 that means
|
| +** that a search record formed from OP_MakeRecord is contained in the
|
| +** single memory location iPk.
|
| +**
|
| +** eMode:
|
| +** Parameter eMode may be passed either ONEPASS_OFF (0), ONEPASS_SINGLE, or
|
| +** ONEPASS_MULTI. If eMode is not ONEPASS_OFF, then the cursor
|
| +** iDataCur already points to the row to delete. If eMode is ONEPASS_OFF
|
| +** then this function must seek iDataCur to the entry identified by iPk
|
| +** and nPk before reading from it.
|
| +**
|
| +** If eMode is ONEPASS_MULTI, then this call is being made as part
|
| +** of a ONEPASS delete that affects multiple rows. In this case, if
|
| +** iIdxNoSeek is a valid cursor number (>=0), then its position should
|
| +** be preserved following the delete operation. Or, if iIdxNoSeek is not
|
| +** a valid cursor number, the position of iDataCur should be preserved
|
| +** instead.
|
| +**
|
| +** iIdxNoSeek:
|
| +** If iIdxNoSeek is a valid cursor number (>=0), then it identifies an
|
| +** index cursor (from within array of cursors starting at iIdxCur) that
|
| +** already points to the index entry to be deleted.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3GenerateRowDelete(
|
| + Parse *pParse, /* Parsing context */
|
| + Table *pTab, /* Table containing the row to be deleted */
|
| + Trigger *pTrigger, /* List of triggers to (potentially) fire */
|
| + int iDataCur, /* Cursor from which column data is extracted */
|
| + int iIdxCur, /* First index cursor */
|
| + int iPk, /* First memory cell containing the PRIMARY KEY */
|
| + i16 nPk, /* Number of PRIMARY KEY memory cells */
|
| + u8 count, /* If non-zero, increment the row change counter */
|
| + u8 onconf, /* Default ON CONFLICT policy for triggers */
|
| + u8 eMode, /* ONEPASS_OFF, _SINGLE, or _MULTI. See above */
|
| + int iIdxNoSeek /* Cursor number of cursor that does not need seeking */
|
| +){
|
| + Vdbe *v = pParse->pVdbe; /* Vdbe */
|
| + int iOld = 0; /* First register in OLD.* array */
|
| + int iLabel; /* Label resolved to end of generated code */
|
| + u8 opSeek; /* Seek opcode */
|
| +
|
| + /* Vdbe is guaranteed to have been allocated by this stage. */
|
| + assert( v );
|
| + VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)",
|
| + iDataCur, iIdxCur, iPk, (int)nPk));
|
| +
|
| + /* Seek cursor iCur to the row to delete. If this row no longer exists
|
| + ** (this can happen if a trigger program has already deleted it), do
|
| + ** not attempt to delete it or fire any DELETE triggers. */
|
| + iLabel = sqlite3VdbeMakeLabel(v);
|
| + opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
|
| + if( eMode==ONEPASS_OFF ){
|
| + sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
|
| + VdbeCoverageIf(v, opSeek==OP_NotExists);
|
| + VdbeCoverageIf(v, opSeek==OP_NotFound);
|
| + }
|
| +
|
| + /* If there are any triggers to fire, allocate a range of registers to
|
| + ** use for the old.* references in the triggers. */
|
| + if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){
|
| + u32 mask; /* Mask of OLD.* columns in use */
|
| + int iCol; /* Iterator used while populating OLD.* */
|
| + int addrStart; /* Start of BEFORE trigger programs */
|
| +
|
| + /* TODO: Could use temporary registers here. Also could attempt to
|
| + ** avoid copying the contents of the rowid register. */
|
| + mask = sqlite3TriggerColmask(
|
| + pParse, pTrigger, 0, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onconf
|
| + );
|
| + mask |= sqlite3FkOldmask(pParse, pTab);
|
| + iOld = pParse->nMem+1;
|
| + pParse->nMem += (1 + pTab->nCol);
|
| +
|
| + /* Populate the OLD.* pseudo-table register array. These values will be
|
| + ** used by any BEFORE and AFTER triggers that exist. */
|
| + sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld);
|
| + for(iCol=0; iCol<pTab->nCol; iCol++){
|
| + testcase( mask!=0xffffffff && iCol==31 );
|
| + testcase( mask!=0xffffffff && iCol==32 );
|
| + if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){
|
| + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1);
|
| + }
|
| + }
|
| +
|
| + /* Invoke BEFORE DELETE trigger programs. */
|
| + addrStart = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3CodeRowTrigger(pParse, pTrigger,
|
| + TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel
|
| + );
|
| +
|
| + /* If any BEFORE triggers were coded, then seek the cursor to the
|
| + ** row to be deleted again. It may be that the BEFORE triggers moved
|
| + ** the cursor or of already deleted the row that the cursor was
|
| + ** pointing to.
|
| + */
|
| + if( addrStart<sqlite3VdbeCurrentAddr(v) ){
|
| + sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
|
| + VdbeCoverageIf(v, opSeek==OP_NotExists);
|
| + VdbeCoverageIf(v, opSeek==OP_NotFound);
|
| + }
|
| +
|
| + /* Do FK processing. This call checks that any FK constraints that
|
| + ** refer to this table (i.e. constraints attached to other tables)
|
| + ** are not violated by deleting this row. */
|
| + sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0);
|
| + }
|
| +
|
| + /* Delete the index and table entries. Skip this step if pTab is really
|
| + ** a view (in which case the only effect of the DELETE statement is to
|
| + ** fire the INSTEAD OF triggers). */
|
| + if( pTab->pSelect==0 ){
|
| + sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
|
| + sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
|
| + if( count ){
|
| + sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
| + }
|
| + if( iIdxNoSeek>=0 ){
|
| + sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
|
| + }
|
| + sqlite3VdbeChangeP5(v, eMode==ONEPASS_MULTI);
|
| + }
|
| +
|
| + /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
| + ** handle rows (possibly in other tables) that refer via a foreign key
|
| + ** to the row just deleted. */
|
| + sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
|
| +
|
| + /* Invoke AFTER DELETE trigger programs. */
|
| + sqlite3CodeRowTrigger(pParse, pTrigger,
|
| + TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
|
| + );
|
| +
|
| + /* Jump here if the row had already been deleted before any BEFORE
|
| + ** trigger programs were invoked. Or if a trigger program throws a
|
| + ** RAISE(IGNORE) exception. */
|
| + sqlite3VdbeResolveLabel(v, iLabel);
|
| + VdbeModuleComment((v, "END: GenRowDel()"));
|
| +}
|
| +
|
| +/*
|
| +** This routine generates VDBE code that causes the deletion of all
|
| +** index entries associated with a single row of a single table, pTab
|
| +**
|
| +** Preconditions:
|
| +**
|
| +** 1. A read/write cursor "iDataCur" must be open on the canonical storage
|
| +** btree for the table pTab. (This will be either the table itself
|
| +** for rowid tables or to the primary key index for WITHOUT ROWID
|
| +** tables.)
|
| +**
|
| +** 2. Read/write cursors for all indices of pTab must be open as
|
| +** cursor number iIdxCur+i for the i-th index. (The pTab->pIndex
|
| +** index is the 0-th index.)
|
| +**
|
| +** 3. The "iDataCur" cursor must be already be positioned on 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 iDataCur, /* Cursor of table holding data. */
|
| + int iIdxCur, /* First index cursor */
|
| + int *aRegIdx, /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
|
| + int iIdxNoSeek /* Do not delete from this cursor */
|
| +){
|
| + int i; /* Index loop counter */
|
| + int r1 = -1; /* Register holding an index key */
|
| + int iPartIdxLabel; /* Jump destination for skipping partial index entries */
|
| + Index *pIdx; /* Current index */
|
| + Index *pPrior = 0; /* Prior index */
|
| + Vdbe *v; /* The prepared statement under construction */
|
| + Index *pPk; /* PRIMARY KEY index, or NULL for rowid tables */
|
| +
|
| + v = pParse->pVdbe;
|
| + pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
| + for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
| + assert( iIdxCur+i!=iDataCur || pPk==pIdx );
|
| + if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
|
| + if( pIdx==pPk ) continue;
|
| + if( iIdxCur+i==iIdxNoSeek ) continue;
|
| + VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
|
| + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
|
| + &iPartIdxLabel, pPrior, r1);
|
| + sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
| + pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
| + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
| + pPrior = pIdx;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Generate code that will assemble an index key and stores 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. If pTab is a WITHOUT ROWID table, then
|
| +** iCur must be the cursor of the PRIMARY KEY index.
|
| +**
|
| +** 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.
|
| +**
|
| +** If *piPartIdxLabel is not NULL, fill it in with a label and jump
|
| +** to that label if pIdx is a partial index that should be skipped.
|
| +** The label should be resolved using sqlite3ResolvePartIdxLabel().
|
| +** A partial index should be skipped if its WHERE clause evaluates
|
| +** to false or null. If pIdx is not a partial index, *piPartIdxLabel
|
| +** will be set to zero which is an empty label that is ignored by
|
| +** sqlite3ResolvePartIdxLabel().
|
| +**
|
| +** The pPrior and regPrior parameters are used to implement a cache to
|
| +** avoid unnecessary register loads. If pPrior is not NULL, then it is
|
| +** a pointer to a different index for which an index key has just been
|
| +** computed into register regPrior. If the current pIdx index is generating
|
| +** its key into the same sequence of registers and if pPrior and pIdx share
|
| +** a column in common, then the register corresponding to that column already
|
| +** holds the correct value and the loading of that register is skipped.
|
| +** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK
|
| +** on a table with multiple indices, and especially with the ROWID or
|
| +** PRIMARY KEY columns of the index.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3GenerateIndexKey(
|
| + Parse *pParse, /* Parsing context */
|
| + Index *pIdx, /* The index for which to generate a key */
|
| + int iDataCur, /* Cursor number from which to take column data */
|
| + int regOut, /* Put the new key into this register if not 0 */
|
| + int prefixOnly, /* Compute only a unique prefix of the key */
|
| + int *piPartIdxLabel, /* OUT: Jump to this label to skip partial index */
|
| + Index *pPrior, /* Previously generated index key */
|
| + int regPrior /* Register holding previous generated key */
|
| +){
|
| + Vdbe *v = pParse->pVdbe;
|
| + int j;
|
| + int regBase;
|
| + int nCol;
|
| +
|
| + if( piPartIdxLabel ){
|
| + if( pIdx->pPartIdxWhere ){
|
| + *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
|
| + pParse->iSelfTab = iDataCur;
|
| + sqlite3ExprCachePush(pParse);
|
| + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
| + SQLITE_JUMPIFNULL);
|
| + }else{
|
| + *piPartIdxLabel = 0;
|
| + }
|
| + }
|
| + nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
|
| + regBase = sqlite3GetTempRange(pParse, nCol);
|
| + if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0;
|
| + for(j=0; j<nCol; j++){
|
| + if( pPrior
|
| + && pPrior->aiColumn[j]==pIdx->aiColumn[j]
|
| + && pPrior->aiColumn[j]!=XN_EXPR
|
| + ){
|
| + /* This column was already computed by the previous index */
|
| + continue;
|
| + }
|
| + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
|
| + /* If the column affinity is REAL but the number is an integer, then it
|
| + ** might be stored in the table as an integer (using a compact
|
| + ** representation) then converted to REAL by an OP_RealAffinity opcode.
|
| + ** But we are getting ready to store this value back into an index, where
|
| + ** it should be converted by to INTEGER again. So omit the OP_RealAffinity
|
| + ** opcode if it is present */
|
| + sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity);
|
| + }
|
| + if( regOut ){
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
|
| + }
|
| + sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
| + return regBase;
|
| +}
|
| +
|
| +/*
|
| +** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label
|
| +** because it was a partial index, then this routine should be called to
|
| +** resolve that label.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
|
| + if( iLabel ){
|
| + sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
|
| + sqlite3ExprCachePop(pParse);
|
| + }
|
| +}
|
| +
|
| +/************** End of delete.c **********************************************/
|
| +/************** Begin file func.c ********************************************/
|
| +/*
|
| +** 2002 February 23
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains the C-language implementations for many of the SQL
|
| +** functions of SQLite. (Some function, and in particular the date and
|
| +** time functions, are implemented separately.)
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +/* #include <stdlib.h> */
|
| +/* #include <assert.h> */
|
| +/* #include "vdbeInt.h" */
|
| +
|
| +/*
|
| +** Return the collating function associated with a function.
|
| +*/
|
| +static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
|
| + VdbeOp *pOp;
|
| + assert( context->pVdbe!=0 );
|
| + pOp = &context->pVdbe->aOp[context->iOp-1];
|
| + assert( pOp->opcode==OP_CollSeq );
|
| + assert( pOp->p4type==P4_COLLSEQ );
|
| + return pOp->p4.pColl;
|
| +}
|
| +
|
| +/*
|
| +** Indicate that the accumulator load should be skipped on this
|
| +** iteration of the aggregate loop.
|
| +*/
|
| +static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){
|
| + context->skipFlag = 1;
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the non-aggregate min() and max() functions
|
| +*/
|
| +static void minmaxFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + int i;
|
| + int mask; /* 0 for min() or 0xffffffff for max() */
|
| + int iBest;
|
| + CollSeq *pColl;
|
| +
|
| + assert( argc>1 );
|
| + mask = sqlite3_user_data(context)==0 ? 0 : -1;
|
| + pColl = sqlite3GetFuncCollSeq(context);
|
| + assert( pColl );
|
| + assert( mask==-1 || mask==0 );
|
| + iBest = 0;
|
| + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
| + for(i=1; i<argc; i++){
|
| + if( sqlite3_value_type(argv[i])==SQLITE_NULL ) return;
|
| + if( (sqlite3MemCompare(argv[iBest], argv[i], pColl)^mask)>=0 ){
|
| + testcase( mask==0 );
|
| + iBest = i;
|
| + }
|
| + }
|
| + sqlite3_result_value(context, argv[iBest]);
|
| +}
|
| +
|
| +/*
|
| +** Return the type of the argument.
|
| +*/
|
| +static void typeofFunc(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **argv
|
| +){
|
| + const char *z = 0;
|
| + UNUSED_PARAMETER(NotUsed);
|
| + switch( sqlite3_value_type(argv[0]) ){
|
| + case SQLITE_INTEGER: z = "integer"; break;
|
| + case SQLITE_TEXT: z = "text"; break;
|
| + case SQLITE_FLOAT: z = "real"; break;
|
| + case SQLITE_BLOB: z = "blob"; break;
|
| + default: z = "null"; break;
|
| + }
|
| + sqlite3_result_text(context, z, -1, SQLITE_STATIC);
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Implementation of the length() function
|
| +*/
|
| +static void lengthFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + int len;
|
| +
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + switch( sqlite3_value_type(argv[0]) ){
|
| + case SQLITE_BLOB:
|
| + case SQLITE_INTEGER:
|
| + case SQLITE_FLOAT: {
|
| + sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
|
| + break;
|
| + }
|
| + case SQLITE_TEXT: {
|
| + const unsigned char *z = sqlite3_value_text(argv[0]);
|
| + if( z==0 ) return;
|
| + len = 0;
|
| + while( *z ){
|
| + len++;
|
| + SQLITE_SKIP_UTF8(z);
|
| + }
|
| + sqlite3_result_int(context, len);
|
| + break;
|
| + }
|
| + default: {
|
| + sqlite3_result_null(context);
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the abs() function.
|
| +**
|
| +** IMP: R-23979-26855 The abs(X) function returns the absolute value of
|
| +** the numeric argument X.
|
| +*/
|
| +static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + switch( sqlite3_value_type(argv[0]) ){
|
| + case SQLITE_INTEGER: {
|
| + i64 iVal = sqlite3_value_int64(argv[0]);
|
| + if( iVal<0 ){
|
| + if( iVal==SMALLEST_INT64 ){
|
| + /* IMP: R-31676-45509 If X is the integer -9223372036854775808
|
| + ** then abs(X) throws an integer overflow error since there is no
|
| + ** equivalent positive 64-bit two complement value. */
|
| + sqlite3_result_error(context, "integer overflow", -1);
|
| + return;
|
| + }
|
| + iVal = -iVal;
|
| + }
|
| + sqlite3_result_int64(context, iVal);
|
| + break;
|
| + }
|
| + case SQLITE_NULL: {
|
| + /* IMP: R-37434-19929 Abs(X) returns NULL if X is NULL. */
|
| + sqlite3_result_null(context);
|
| + break;
|
| + }
|
| + default: {
|
| + /* Because sqlite3_value_double() returns 0.0 if the argument is not
|
| + ** something that can be converted into a number, we have:
|
| + ** IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob
|
| + ** that cannot be converted to a numeric value.
|
| + */
|
| + double rVal = sqlite3_value_double(argv[0]);
|
| + if( rVal<0 ) rVal = -rVal;
|
| + sqlite3_result_double(context, rVal);
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the instr() function.
|
| +**
|
| +** instr(haystack,needle) finds the first occurrence of needle
|
| +** in haystack and returns the number of previous characters plus 1,
|
| +** or 0 if needle does not occur within haystack.
|
| +**
|
| +** If both haystack and needle are BLOBs, then the result is one more than
|
| +** the number of bytes in haystack prior to the first occurrence of needle,
|
| +** or 0 if needle never occurs in haystack.
|
| +*/
|
| +static void instrFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + const unsigned char *zHaystack;
|
| + const unsigned char *zNeedle;
|
| + int nHaystack;
|
| + int nNeedle;
|
| + int typeHaystack, typeNeedle;
|
| + int N = 1;
|
| + int isText;
|
| +
|
| + UNUSED_PARAMETER(argc);
|
| + typeHaystack = sqlite3_value_type(argv[0]);
|
| + typeNeedle = sqlite3_value_type(argv[1]);
|
| + if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
|
| + nHaystack = sqlite3_value_bytes(argv[0]);
|
| + nNeedle = sqlite3_value_bytes(argv[1]);
|
| + if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
|
| + zHaystack = sqlite3_value_blob(argv[0]);
|
| + zNeedle = sqlite3_value_blob(argv[1]);
|
| + isText = 0;
|
| + }else{
|
| + zHaystack = sqlite3_value_text(argv[0]);
|
| + zNeedle = sqlite3_value_text(argv[1]);
|
| + isText = 1;
|
| + }
|
| + while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
|
| + N++;
|
| + do{
|
| + nHaystack--;
|
| + zHaystack++;
|
| + }while( isText && (zHaystack[0]&0xc0)==0x80 );
|
| + }
|
| + if( nNeedle>nHaystack ) N = 0;
|
| + sqlite3_result_int(context, N);
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the printf() function.
|
| +*/
|
| +static void printfFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + PrintfArguments x;
|
| + StrAccum str;
|
| + const char *zFormat;
|
| + int n;
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| +
|
| + if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){
|
| + x.nArg = argc-1;
|
| + x.nUsed = 0;
|
| + x.apArg = argv+1;
|
| + sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
|
| + sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x);
|
| + n = str.nChar;
|
| + sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
|
| + SQLITE_DYNAMIC);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the substr() function.
|
| +**
|
| +** substr(x,p1,p2) returns p2 characters of x[] beginning with p1.
|
| +** p1 is 1-indexed. So substr(x,1,1) returns the first character
|
| +** of x. If x is text, then we actually count UTF-8 characters.
|
| +** If x is a blob, then we count bytes.
|
| +**
|
| +** If p1 is negative, then we begin abs(p1) from the end of x[].
|
| +**
|
| +** If p2 is negative, return the p2 characters preceding p1.
|
| +*/
|
| +static void substrFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + const unsigned char *z;
|
| + const unsigned char *z2;
|
| + int len;
|
| + int p0type;
|
| + i64 p1, p2;
|
| + int negP2 = 0;
|
| +
|
| + assert( argc==3 || argc==2 );
|
| + if( sqlite3_value_type(argv[1])==SQLITE_NULL
|
| + || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL)
|
| + ){
|
| + return;
|
| + }
|
| + p0type = sqlite3_value_type(argv[0]);
|
| + p1 = sqlite3_value_int(argv[1]);
|
| + if( p0type==SQLITE_BLOB ){
|
| + len = sqlite3_value_bytes(argv[0]);
|
| + z = sqlite3_value_blob(argv[0]);
|
| + if( z==0 ) return;
|
| + assert( len==sqlite3_value_bytes(argv[0]) );
|
| + }else{
|
| + z = sqlite3_value_text(argv[0]);
|
| + if( z==0 ) return;
|
| + len = 0;
|
| + if( p1<0 ){
|
| + for(z2=z; *z2; len++){
|
| + SQLITE_SKIP_UTF8(z2);
|
| + }
|
| + }
|
| + }
|
| +#ifdef SQLITE_SUBSTR_COMPATIBILITY
|
| + /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
|
| + ** as substr(X,1,N) - it returns the first N characters of X. This
|
| + ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
|
| + ** from 2009-02-02 for compatibility of applications that exploited the
|
| + ** old buggy behavior. */
|
| + if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
|
| +#endif
|
| + if( argc==3 ){
|
| + p2 = sqlite3_value_int(argv[2]);
|
| + if( p2<0 ){
|
| + p2 = -p2;
|
| + negP2 = 1;
|
| + }
|
| + }else{
|
| + p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH];
|
| + }
|
| + if( p1<0 ){
|
| + p1 += len;
|
| + if( p1<0 ){
|
| + p2 += p1;
|
| + if( p2<0 ) p2 = 0;
|
| + p1 = 0;
|
| + }
|
| + }else if( p1>0 ){
|
| + p1--;
|
| + }else if( p2>0 ){
|
| + p2--;
|
| + }
|
| + if( negP2 ){
|
| + p1 -= p2;
|
| + if( p1<0 ){
|
| + p2 += p1;
|
| + p1 = 0;
|
| + }
|
| + }
|
| + assert( p1>=0 && p2>=0 );
|
| + if( p0type!=SQLITE_BLOB ){
|
| + while( *z && p1 ){
|
| + SQLITE_SKIP_UTF8(z);
|
| + p1--;
|
| + }
|
| + for(z2=z; *z2 && p2; p2--){
|
| + SQLITE_SKIP_UTF8(z2);
|
| + }
|
| + sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT,
|
| + SQLITE_UTF8);
|
| + }else{
|
| + if( p1+p2>len ){
|
| + p2 = len-p1;
|
| + if( p2<0 ) p2 = 0;
|
| + }
|
| + sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the round() function
|
| +*/
|
| +#ifndef SQLITE_OMIT_FLOATING_POINT
|
| +static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
| + int n = 0;
|
| + double r;
|
| + char *zBuf;
|
| + assert( argc==1 || argc==2 );
|
| + if( argc==2 ){
|
| + if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return;
|
| + n = sqlite3_value_int(argv[1]);
|
| + if( n>30 ) n = 30;
|
| + if( n<0 ) n = 0;
|
| + }
|
| + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
| + r = sqlite3_value_double(argv[0]);
|
| + /* If Y==0 and X will fit in a 64-bit int,
|
| + ** handle the rounding directly,
|
| + ** otherwise use printf.
|
| + */
|
| + if( n==0 && r>=0 && r<LARGEST_INT64-1 ){
|
| + r = (double)((sqlite_int64)(r+0.5));
|
| + }else if( n==0 && r<0 && (-r)<LARGEST_INT64-1 ){
|
| + r = -(double)((sqlite_int64)((-r)+0.5));
|
| + }else{
|
| + zBuf = sqlite3_mprintf("%.*f",n,r);
|
| + if( zBuf==0 ){
|
| + sqlite3_result_error_nomem(context);
|
| + return;
|
| + }
|
| + sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8);
|
| + sqlite3_free(zBuf);
|
| + }
|
| + sqlite3_result_double(context, r);
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** Allocate nByte bytes of space using sqlite3Malloc(). If the
|
| +** allocation fails, call sqlite3_result_error_nomem() to notify
|
| +** the database handle that malloc() has failed and return NULL.
|
| +** If nByte is larger than the maximum string or blob length, then
|
| +** raise an SQLITE_TOOBIG exception and return NULL.
|
| +*/
|
| +static void *contextMalloc(sqlite3_context *context, i64 nByte){
|
| + char *z;
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + assert( nByte>0 );
|
| + testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH] );
|
| + testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
|
| + if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
| + sqlite3_result_error_toobig(context);
|
| + z = 0;
|
| + }else{
|
| + z = sqlite3Malloc(nByte);
|
| + if( !z ){
|
| + sqlite3_result_error_nomem(context);
|
| + }
|
| + }
|
| + return z;
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the upper() and lower() SQL functions.
|
| +*/
|
| +static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
| + char *z1;
|
| + const char *z2;
|
| + int i, n;
|
| + UNUSED_PARAMETER(argc);
|
| + z2 = (char*)sqlite3_value_text(argv[0]);
|
| + n = sqlite3_value_bytes(argv[0]);
|
| + /* Verify that the call to _bytes() does not invalidate the _text() pointer */
|
| + assert( z2==(char*)sqlite3_value_text(argv[0]) );
|
| + if( z2 ){
|
| + z1 = contextMalloc(context, ((i64)n)+1);
|
| + if( z1 ){
|
| + for(i=0; i<n; i++){
|
| + z1[i] = (char)sqlite3Toupper(z2[i]);
|
| + }
|
| + sqlite3_result_text(context, z1, n, sqlite3_free);
|
| + }
|
| + }
|
| +}
|
| +static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
| + char *z1;
|
| + const char *z2;
|
| + int i, n;
|
| + UNUSED_PARAMETER(argc);
|
| + z2 = (char*)sqlite3_value_text(argv[0]);
|
| + n = sqlite3_value_bytes(argv[0]);
|
| + /* Verify that the call to _bytes() does not invalidate the _text() pointer */
|
| + assert( z2==(char*)sqlite3_value_text(argv[0]) );
|
| + if( z2 ){
|
| + z1 = contextMalloc(context, ((i64)n)+1);
|
| + if( z1 ){
|
| + for(i=0; i<n; i++){
|
| + z1[i] = sqlite3Tolower(z2[i]);
|
| + }
|
| + sqlite3_result_text(context, z1, n, sqlite3_free);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Some functions like COALESCE() and IFNULL() and UNLIKELY() are implemented
|
| +** as VDBE code so that unused argument values do not have to be computed.
|
| +** However, we still need some kind of function implementation for this
|
| +** routines in the function table. The noopFunc macro provides this.
|
| +** noopFunc will never be called so it doesn't matter what the implementation
|
| +** is. We might as well use the "version()" function as a substitute.
|
| +*/
|
| +#define noopFunc versionFunc /* Substitute function - never called */
|
| +
|
| +/*
|
| +** Implementation of random(). Return a random integer.
|
| +*/
|
| +static void randomFunc(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **NotUsed2
|
| +){
|
| + sqlite_int64 r;
|
| + UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
| + sqlite3_randomness(sizeof(r), &r);
|
| + if( r<0 ){
|
| + /* We need to prevent a random number of 0x8000000000000000
|
| + ** (or -9223372036854775808) since when you do abs() of that
|
| + ** number of you get the same value back again. To do this
|
| + ** in a way that is testable, mask the sign bit off of negative
|
| + ** values, resulting in a positive value. Then take the
|
| + ** 2s complement of that positive value. The end result can
|
| + ** therefore be no less than -9223372036854775807.
|
| + */
|
| + r = -(r & LARGEST_INT64);
|
| + }
|
| + sqlite3_result_int64(context, r);
|
| +}
|
| +
|
| +/*
|
| +** Implementation of randomblob(N). Return a random blob
|
| +** that is N bytes long.
|
| +*/
|
| +static void randomBlob(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + int n;
|
| + unsigned char *p;
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + n = sqlite3_value_int(argv[0]);
|
| + if( n<1 ){
|
| + n = 1;
|
| + }
|
| + p = contextMalloc(context, n);
|
| + if( p ){
|
| + sqlite3_randomness(n, p);
|
| + sqlite3_result_blob(context, (char*)p, n, sqlite3_free);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the last_insert_rowid() SQL function. The return
|
| +** value is the same as the sqlite3_last_insert_rowid() API function.
|
| +*/
|
| +static void last_insert_rowid(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **NotUsed2
|
| +){
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
| + /* IMP: R-51513-12026 The last_insert_rowid() SQL function is a
|
| + ** wrapper around the sqlite3_last_insert_rowid() C/C++ interface
|
| + ** function. */
|
| + sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the changes() SQL function.
|
| +**
|
| +** IMP: R-62073-11209 The changes() SQL function is a wrapper
|
| +** around the sqlite3_changes() C/C++ function and hence follows the same
|
| +** rules for counting changes.
|
| +*/
|
| +static void changes(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **NotUsed2
|
| +){
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
| + sqlite3_result_int(context, sqlite3_changes(db));
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the total_changes() SQL function. The return value is
|
| +** the same as the sqlite3_total_changes() API function.
|
| +*/
|
| +static void total_changes(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **NotUsed2
|
| +){
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
| + /* IMP: R-52756-41993 This function is a wrapper around the
|
| + ** sqlite3_total_changes() C/C++ interface. */
|
| + sqlite3_result_int(context, sqlite3_total_changes(db));
|
| +}
|
| +
|
| +/*
|
| +** A structure defining how to do GLOB-style comparisons.
|
| +*/
|
| +struct compareInfo {
|
| + u8 matchAll;
|
| + u8 matchOne;
|
| + u8 matchSet;
|
| + u8 noCase;
|
| +};
|
| +
|
| +/*
|
| +** For LIKE and GLOB matching on EBCDIC machines, assume that every
|
| +** character is exactly one byte in size. Also, provde the Utf8Read()
|
| +** macro for fast reading of the next character in the common case where
|
| +** the next character is ASCII.
|
| +*/
|
| +#if defined(SQLITE_EBCDIC)
|
| +# define sqlite3Utf8Read(A) (*((*A)++))
|
| +# define Utf8Read(A) (*(A++))
|
| +#else
|
| +# define Utf8Read(A) (A[0]<0x80?*(A++):sqlite3Utf8Read(&A))
|
| +#endif
|
| +
|
| +static const struct compareInfo globInfo = { '*', '?', '[', 0 };
|
| +/* The correct SQL-92 behavior is for the LIKE operator to ignore
|
| +** case. Thus 'a' LIKE 'A' would be true. */
|
| +static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };
|
| +/* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator
|
| +** is case sensitive causing 'a' LIKE 'A' to be false */
|
| +static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
|
| +
|
| +/*
|
| +** Compare two UTF-8 strings for equality where the first string can
|
| +** potentially be a "glob" or "like" expression. Return true (1) if they
|
| +** are the same and false (0) if they are different.
|
| +**
|
| +** Globbing rules:
|
| +**
|
| +** '*' Matches any sequence of zero or more characters.
|
| +**
|
| +** '?' Matches exactly one character.
|
| +**
|
| +** [...] Matches one character from the enclosed list of
|
| +** characters.
|
| +**
|
| +** [^...] Matches one character not in the enclosed list.
|
| +**
|
| +** With the [...] and [^...] matching, a ']' character can be included
|
| +** in the list by making it the first character after '[' or '^'. A
|
| +** range of characters can be specified using '-'. Example:
|
| +** "[a-z]" matches any single lower-case letter. To match a '-', make
|
| +** it the last character in the list.
|
| +**
|
| +** Like matching rules:
|
| +**
|
| +** '%' Matches any sequence of zero or more characters
|
| +**
|
| +*** '_' Matches any one character
|
| +**
|
| +** Ec Where E is the "esc" character and c is any other
|
| +** character, including '%', '_', and esc, match exactly c.
|
| +**
|
| +** The comments within this routine usually assume glob matching.
|
| +**
|
| +** This routine is usually quick, but can be N**2 in the worst case.
|
| +*/
|
| +static int patternCompare(
|
| + const u8 *zPattern, /* The glob pattern */
|
| + const u8 *zString, /* The string to compare against the glob */
|
| + const struct compareInfo *pInfo, /* Information about how to do the compare */
|
| + u32 esc /* The escape character */
|
| +){
|
| + u32 c, c2; /* Next pattern and input string chars */
|
| + u32 matchOne = pInfo->matchOne; /* "?" or "_" */
|
| + u32 matchAll = pInfo->matchAll; /* "*" or "%" */
|
| + u32 matchOther; /* "[" or the escape character */
|
| + u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */
|
| + const u8 *zEscaped = 0; /* One past the last escaped input char */
|
| +
|
| + /* The GLOB operator does not have an ESCAPE clause. And LIKE does not
|
| + ** have the matchSet operator. So we either have to look for one or
|
| + ** the other, never both. Hence the single variable matchOther is used
|
| + ** to store the one we have to look for.
|
| + */
|
| + matchOther = esc ? esc : pInfo->matchSet;
|
| +
|
| + while( (c = Utf8Read(zPattern))!=0 ){
|
| + if( c==matchAll ){ /* Match "*" */
|
| + /* Skip over multiple "*" characters in the pattern. If there
|
| + ** are also "?" characters, skip those as well, but consume a
|
| + ** single character of the input string for each "?" skipped */
|
| + while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
|
| + if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
|
| + return 0;
|
| + }
|
| + }
|
| + if( c==0 ){
|
| + return 1; /* "*" at the end of the pattern matches */
|
| + }else if( c==matchOther ){
|
| + if( esc ){
|
| + c = sqlite3Utf8Read(&zPattern);
|
| + if( c==0 ) return 0;
|
| + }else{
|
| + /* "[...]" immediately follows the "*". We have to do a slow
|
| + ** recursive search in this case, but it is an unusual case. */
|
| + assert( matchOther<0x80 ); /* '[' is a single-byte character */
|
| + while( *zString
|
| + && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
|
| + SQLITE_SKIP_UTF8(zString);
|
| + }
|
| + return *zString!=0;
|
| + }
|
| + }
|
| +
|
| + /* At this point variable c contains the first character of the
|
| + ** pattern string past the "*". Search in the input string for the
|
| + ** first matching character and recursively contine the match from
|
| + ** that point.
|
| + **
|
| + ** For a case-insensitive search, set variable cx to be the same as
|
| + ** c but in the other case and search the input string for either
|
| + ** c or cx.
|
| + */
|
| + if( c<=0x80 ){
|
| + u32 cx;
|
| + if( noCase ){
|
| + cx = sqlite3Toupper(c);
|
| + c = sqlite3Tolower(c);
|
| + }else{
|
| + cx = c;
|
| + }
|
| + while( (c2 = *(zString++))!=0 ){
|
| + if( c2!=c && c2!=cx ) continue;
|
| + if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
|
| + }
|
| + }else{
|
| + while( (c2 = Utf8Read(zString))!=0 ){
|
| + if( c2!=c ) continue;
|
| + if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
|
| + }
|
| + }
|
| + return 0;
|
| + }
|
| + if( c==matchOther ){
|
| + if( esc ){
|
| + c = sqlite3Utf8Read(&zPattern);
|
| + if( c==0 ) return 0;
|
| + zEscaped = zPattern;
|
| + }else{
|
| + u32 prior_c = 0;
|
| + int seen = 0;
|
| + int invert = 0;
|
| + c = sqlite3Utf8Read(&zString);
|
| + if( c==0 ) return 0;
|
| + c2 = sqlite3Utf8Read(&zPattern);
|
| + if( c2=='^' ){
|
| + invert = 1;
|
| + c2 = sqlite3Utf8Read(&zPattern);
|
| + }
|
| + if( c2==']' ){
|
| + if( c==']' ) seen = 1;
|
| + c2 = sqlite3Utf8Read(&zPattern);
|
| + }
|
| + while( c2 && c2!=']' ){
|
| + if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
|
| + c2 = sqlite3Utf8Read(&zPattern);
|
| + if( c>=prior_c && c<=c2 ) seen = 1;
|
| + prior_c = 0;
|
| + }else{
|
| + if( c==c2 ){
|
| + seen = 1;
|
| + }
|
| + prior_c = c2;
|
| + }
|
| + c2 = sqlite3Utf8Read(&zPattern);
|
| + }
|
| + if( c2==0 || (seen ^ invert)==0 ){
|
| + return 0;
|
| + }
|
| + continue;
|
| + }
|
| + }
|
| + c2 = Utf8Read(zString);
|
| + if( c==c2 ) continue;
|
| + if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
|
| + continue;
|
| + }
|
| + if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
|
| + return 0;
|
| + }
|
| + return *zString==0;
|
| +}
|
| +
|
| +/*
|
| +** The sqlite3_strglob() interface.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
|
| + return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
|
| +}
|
| +
|
| +/*
|
| +** The sqlite3_strlike() interface.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
|
| + return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc)==0;
|
| +}
|
| +
|
| +/*
|
| +** Count the number of times that the LIKE operator (or GLOB which is
|
| +** just a variation of LIKE) gets called. This is used for testing
|
| +** only.
|
| +*/
|
| +#ifdef SQLITE_TEST
|
| +SQLITE_API int sqlite3_like_count = 0;
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** Implementation of the like() SQL function. This function implements
|
| +** the build-in LIKE operator. The first argument to the function is the
|
| +** pattern and the second argument is the string. So, the SQL statements:
|
| +**
|
| +** A LIKE B
|
| +**
|
| +** is implemented as like(B,A).
|
| +**
|
| +** This same function (with a different compareInfo structure) computes
|
| +** the GLOB operator.
|
| +*/
|
| +static void likeFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + const unsigned char *zA, *zB;
|
| + u32 escape = 0;
|
| + int nPat;
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| +
|
| +#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
| + if( sqlite3_value_type(argv[0])==SQLITE_BLOB
|
| + || sqlite3_value_type(argv[1])==SQLITE_BLOB
|
| + ){
|
| +#ifdef SQLITE_TEST
|
| + sqlite3_like_count++;
|
| +#endif
|
| + sqlite3_result_int(context, 0);
|
| + return;
|
| + }
|
| +#endif
|
| + zB = sqlite3_value_text(argv[0]);
|
| + zA = sqlite3_value_text(argv[1]);
|
| +
|
| + /* Limit the length of the LIKE or GLOB pattern to avoid problems
|
| + ** of deep recursion and N*N behavior in patternCompare().
|
| + */
|
| + nPat = sqlite3_value_bytes(argv[0]);
|
| + testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] );
|
| + testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]+1 );
|
| + if( nPat > db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){
|
| + sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
|
| + return;
|
| + }
|
| + assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */
|
| +
|
| + if( argc==3 ){
|
| + /* The escape character string must consist of a single UTF-8 character.
|
| + ** Otherwise, return an error.
|
| + */
|
| + const unsigned char *zEsc = sqlite3_value_text(argv[2]);
|
| + if( zEsc==0 ) return;
|
| + if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){
|
| + sqlite3_result_error(context,
|
| + "ESCAPE expression must be a single character", -1);
|
| + return;
|
| + }
|
| + escape = sqlite3Utf8Read(&zEsc);
|
| + }
|
| + if( zA && zB ){
|
| + struct compareInfo *pInfo = sqlite3_user_data(context);
|
| +#ifdef SQLITE_TEST
|
| + sqlite3_like_count++;
|
| +#endif
|
| +
|
| + sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the NULLIF(x,y) function. The result is the first
|
| +** argument if the arguments are different. The result is NULL if the
|
| +** arguments are equal to each other.
|
| +*/
|
| +static void nullifFunc(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **argv
|
| +){
|
| + CollSeq *pColl = sqlite3GetFuncCollSeq(context);
|
| + UNUSED_PARAMETER(NotUsed);
|
| + if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){
|
| + sqlite3_result_value(context, argv[0]);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the sqlite_version() function. The result is the version
|
| +** of the SQLite library that is running.
|
| +*/
|
| +static void versionFunc(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **NotUsed2
|
| +){
|
| + UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
| + /* IMP: R-48699-48617 This function is an SQL wrapper around the
|
| + ** sqlite3_libversion() C-interface. */
|
| + sqlite3_result_text(context, sqlite3_libversion(), -1, SQLITE_STATIC);
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the sqlite_source_id() function. The result is a string
|
| +** that identifies the particular version of the source code used to build
|
| +** SQLite.
|
| +*/
|
| +static void sourceidFunc(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **NotUsed2
|
| +){
|
| + UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
| + /* IMP: R-24470-31136 This function is an SQL wrapper around the
|
| + ** sqlite3_sourceid() C interface. */
|
| + sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC);
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the sqlite_log() function. This is a wrapper around
|
| +** sqlite3_log(). The return value is NULL. The function exists purely for
|
| +** its side-effects.
|
| +*/
|
| +static void errlogFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + UNUSED_PARAMETER(argc);
|
| + UNUSED_PARAMETER(context);
|
| + sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1]));
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the sqlite_compileoption_used() function.
|
| +** The result is an integer that identifies if the compiler option
|
| +** was used to build SQLite.
|
| +*/
|
| +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
| +static void compileoptionusedFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + const char *zOptName;
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + /* IMP: R-39564-36305 The sqlite_compileoption_used() SQL
|
| + ** function is a wrapper around the sqlite3_compileoption_used() C/C++
|
| + ** function.
|
| + */
|
| + if( (zOptName = (const char*)sqlite3_value_text(argv[0]))!=0 ){
|
| + sqlite3_result_int(context, sqlite3_compileoption_used(zOptName));
|
| + }
|
| +}
|
| +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
| +
|
| +/*
|
| +** Implementation of the sqlite_compileoption_get() function.
|
| +** The result is a string that identifies the compiler options
|
| +** used to build SQLite.
|
| +*/
|
| +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
| +static void compileoptiongetFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + int n;
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + /* IMP: R-04922-24076 The sqlite_compileoption_get() SQL function
|
| + ** is a wrapper around the sqlite3_compileoption_get() C/C++ function.
|
| + */
|
| + n = sqlite3_value_int(argv[0]);
|
| + sqlite3_result_text(context, sqlite3_compileoption_get(n), -1, SQLITE_STATIC);
|
| +}
|
| +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
| +
|
| +/* Array for converting from half-bytes (nybbles) into ASCII hex
|
| +** digits. */
|
| +static const char hexdigits[] = {
|
| + '0', '1', '2', '3', '4', '5', '6', '7',
|
| + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
| +};
|
| +
|
| +/*
|
| +** Implementation of the QUOTE() function. This function takes a single
|
| +** argument. If the argument is numeric, the return value is the same as
|
| +** the argument. If the argument is NULL, the return value is the string
|
| +** "NULL". Otherwise, the argument is enclosed in single quotes with
|
| +** single-quote escapes.
|
| +*/
|
| +static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + switch( sqlite3_value_type(argv[0]) ){
|
| + case SQLITE_FLOAT: {
|
| + double r1, r2;
|
| + char zBuf[50];
|
| + r1 = sqlite3_value_double(argv[0]);
|
| + sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1);
|
| + sqlite3AtoF(zBuf, &r2, 20, SQLITE_UTF8);
|
| + if( r1!=r2 ){
|
| + sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.20e", r1);
|
| + }
|
| + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
| + break;
|
| + }
|
| + case SQLITE_INTEGER: {
|
| + sqlite3_result_value(context, argv[0]);
|
| + break;
|
| + }
|
| + case SQLITE_BLOB: {
|
| + char *zText = 0;
|
| + char const *zBlob = sqlite3_value_blob(argv[0]);
|
| + int nBlob = sqlite3_value_bytes(argv[0]);
|
| + assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
|
| + zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4);
|
| + if( zText ){
|
| + int i;
|
| + for(i=0; i<nBlob; i++){
|
| + zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F];
|
| + zText[(i*2)+3] = hexdigits[(zBlob[i])&0x0F];
|
| + }
|
| + zText[(nBlob*2)+2] = '\'';
|
| + zText[(nBlob*2)+3] = '\0';
|
| + zText[0] = 'X';
|
| + zText[1] = '\'';
|
| + sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
|
| + sqlite3_free(zText);
|
| + }
|
| + break;
|
| + }
|
| + case SQLITE_TEXT: {
|
| + int i,j;
|
| + u64 n;
|
| + const unsigned char *zArg = sqlite3_value_text(argv[0]);
|
| + char *z;
|
| +
|
| + if( zArg==0 ) return;
|
| + for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
|
| + z = contextMalloc(context, ((i64)i)+((i64)n)+3);
|
| + if( z ){
|
| + z[0] = '\'';
|
| + for(i=0, j=1; zArg[i]; i++){
|
| + z[j++] = zArg[i];
|
| + if( zArg[i]=='\'' ){
|
| + z[j++] = '\'';
|
| + }
|
| + }
|
| + z[j++] = '\'';
|
| + z[j] = 0;
|
| + sqlite3_result_text(context, z, j, sqlite3_free);
|
| + }
|
| + break;
|
| + }
|
| + default: {
|
| + assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
|
| + sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** The unicode() function. Return the integer unicode code-point value
|
| +** for the first character of the input string.
|
| +*/
|
| +static void unicodeFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + const unsigned char *z = sqlite3_value_text(argv[0]);
|
| + (void)argc;
|
| + if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z));
|
| +}
|
| +
|
| +/*
|
| +** The char() function takes zero or more arguments, each of which is
|
| +** an integer. It constructs a string where each character of the string
|
| +** is the unicode character for the corresponding integer argument.
|
| +*/
|
| +static void charFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + unsigned char *z, *zOut;
|
| + int i;
|
| + zOut = z = sqlite3_malloc64( argc*4+1 );
|
| + if( z==0 ){
|
| + sqlite3_result_error_nomem(context);
|
| + return;
|
| + }
|
| + for(i=0; i<argc; i++){
|
| + sqlite3_int64 x;
|
| + unsigned c;
|
| + x = sqlite3_value_int64(argv[i]);
|
| + if( x<0 || x>0x10ffff ) x = 0xfffd;
|
| + c = (unsigned)(x & 0x1fffff);
|
| + if( c<0x00080 ){
|
| + *zOut++ = (u8)(c&0xFF);
|
| + }else if( c<0x00800 ){
|
| + *zOut++ = 0xC0 + (u8)((c>>6)&0x1F);
|
| + *zOut++ = 0x80 + (u8)(c & 0x3F);
|
| + }else if( c<0x10000 ){
|
| + *zOut++ = 0xE0 + (u8)((c>>12)&0x0F);
|
| + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
|
| + *zOut++ = 0x80 + (u8)(c & 0x3F);
|
| + }else{
|
| + *zOut++ = 0xF0 + (u8)((c>>18) & 0x07);
|
| + *zOut++ = 0x80 + (u8)((c>>12) & 0x3F);
|
| + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
|
| + *zOut++ = 0x80 + (u8)(c & 0x3F);
|
| + } \
|
| + }
|
| + sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
|
| +}
|
| +
|
| +/*
|
| +** The hex() function. Interpret the argument as a blob. Return
|
| +** a hexadecimal rendering as text.
|
| +*/
|
| +static void hexFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + int i, n;
|
| + const unsigned char *pBlob;
|
| + char *zHex, *z;
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + pBlob = sqlite3_value_blob(argv[0]);
|
| + n = sqlite3_value_bytes(argv[0]);
|
| + assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
|
| + z = zHex = contextMalloc(context, ((i64)n)*2 + 1);
|
| + if( zHex ){
|
| + for(i=0; i<n; i++, pBlob++){
|
| + unsigned char c = *pBlob;
|
| + *(z++) = hexdigits[(c>>4)&0xf];
|
| + *(z++) = hexdigits[c&0xf];
|
| + }
|
| + *z = 0;
|
| + sqlite3_result_text(context, zHex, n*2, sqlite3_free);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** The zeroblob(N) function returns a zero-filled blob of size N bytes.
|
| +*/
|
| +static void zeroblobFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + i64 n;
|
| + int rc;
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + n = sqlite3_value_int64(argv[0]);
|
| + if( n<0 ) n = 0;
|
| + rc = sqlite3_result_zeroblob64(context, n); /* IMP: R-00293-64994 */
|
| + if( rc ){
|
| + sqlite3_result_error_code(context, rc);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** The replace() function. Three arguments are all strings: call
|
| +** them A, B, and C. The result is also a string which is derived
|
| +** from A by replacing every occurrence of B with C. The match
|
| +** must be exact. Collating sequences are not used.
|
| +*/
|
| +static void replaceFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + const unsigned char *zStr; /* The input string A */
|
| + const unsigned char *zPattern; /* The pattern string B */
|
| + const unsigned char *zRep; /* The replacement string C */
|
| + unsigned char *zOut; /* The output */
|
| + int nStr; /* Size of zStr */
|
| + int nPattern; /* Size of zPattern */
|
| + int nRep; /* Size of zRep */
|
| + i64 nOut; /* Maximum size of zOut */
|
| + int loopLimit; /* Last zStr[] that might match zPattern[] */
|
| + int i, j; /* Loop counters */
|
| +
|
| + assert( argc==3 );
|
| + UNUSED_PARAMETER(argc);
|
| + zStr = sqlite3_value_text(argv[0]);
|
| + if( zStr==0 ) return;
|
| + nStr = sqlite3_value_bytes(argv[0]);
|
| + assert( zStr==sqlite3_value_text(argv[0]) ); /* No encoding change */
|
| + zPattern = sqlite3_value_text(argv[1]);
|
| + if( zPattern==0 ){
|
| + assert( sqlite3_value_type(argv[1])==SQLITE_NULL
|
| + || sqlite3_context_db_handle(context)->mallocFailed );
|
| + return;
|
| + }
|
| + if( zPattern[0]==0 ){
|
| + assert( sqlite3_value_type(argv[1])!=SQLITE_NULL );
|
| + sqlite3_result_value(context, argv[0]);
|
| + return;
|
| + }
|
| + nPattern = sqlite3_value_bytes(argv[1]);
|
| + assert( zPattern==sqlite3_value_text(argv[1]) ); /* No encoding change */
|
| + zRep = sqlite3_value_text(argv[2]);
|
| + if( zRep==0 ) return;
|
| + nRep = sqlite3_value_bytes(argv[2]);
|
| + assert( zRep==sqlite3_value_text(argv[2]) );
|
| + nOut = nStr + 1;
|
| + assert( nOut<SQLITE_MAX_LENGTH );
|
| + zOut = contextMalloc(context, (i64)nOut);
|
| + if( zOut==0 ){
|
| + return;
|
| + }
|
| + loopLimit = nStr - nPattern;
|
| + for(i=j=0; i<=loopLimit; i++){
|
| + if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
|
| + zOut[j++] = zStr[i];
|
| + }else{
|
| + u8 *zOld;
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + nOut += nRep - nPattern;
|
| + testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] );
|
| + testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
|
| + if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
| + sqlite3_result_error_toobig(context);
|
| + sqlite3_free(zOut);
|
| + return;
|
| + }
|
| + zOld = zOut;
|
| + zOut = sqlite3_realloc64(zOut, (int)nOut);
|
| + if( zOut==0 ){
|
| + sqlite3_result_error_nomem(context);
|
| + sqlite3_free(zOld);
|
| + return;
|
| + }
|
| + memcpy(&zOut[j], zRep, nRep);
|
| + j += nRep;
|
| + i += nPattern-1;
|
| + }
|
| + }
|
| + assert( j+nStr-i+1==nOut );
|
| + memcpy(&zOut[j], &zStr[i], nStr-i);
|
| + j += nStr - i;
|
| + assert( j<=nOut );
|
| + zOut[j] = 0;
|
| + sqlite3_result_text(context, (char*)zOut, j, sqlite3_free);
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the TRIM(), LTRIM(), and RTRIM() functions.
|
| +** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both.
|
| +*/
|
| +static void trimFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + const unsigned char *zIn; /* Input string */
|
| + const unsigned char *zCharSet; /* Set of characters to trim */
|
| + int nIn; /* Number of bytes in input */
|
| + int flags; /* 1: trimleft 2: trimright 3: trim */
|
| + int i; /* Loop counter */
|
| + unsigned char *aLen = 0; /* Length of each character in zCharSet */
|
| + unsigned char **azChar = 0; /* Individual characters in zCharSet */
|
| + int nChar; /* Number of characters in zCharSet */
|
| +
|
| + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
|
| + return;
|
| + }
|
| + zIn = sqlite3_value_text(argv[0]);
|
| + if( zIn==0 ) return;
|
| + nIn = sqlite3_value_bytes(argv[0]);
|
| + assert( zIn==sqlite3_value_text(argv[0]) );
|
| + if( argc==1 ){
|
| + static const unsigned char lenOne[] = { 1 };
|
| + static unsigned char * const azOne[] = { (u8*)" " };
|
| + nChar = 1;
|
| + aLen = (u8*)lenOne;
|
| + azChar = (unsigned char **)azOne;
|
| + zCharSet = 0;
|
| + }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){
|
| + return;
|
| + }else{
|
| + const unsigned char *z;
|
| + for(z=zCharSet, nChar=0; *z; nChar++){
|
| + SQLITE_SKIP_UTF8(z);
|
| + }
|
| + if( nChar>0 ){
|
| + azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+1));
|
| + if( azChar==0 ){
|
| + return;
|
| + }
|
| + aLen = (unsigned char*)&azChar[nChar];
|
| + for(z=zCharSet, nChar=0; *z; nChar++){
|
| + azChar[nChar] = (unsigned char *)z;
|
| + SQLITE_SKIP_UTF8(z);
|
| + aLen[nChar] = (u8)(z - azChar[nChar]);
|
| + }
|
| + }
|
| + }
|
| + if( nChar>0 ){
|
| + flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context));
|
| + if( flags & 1 ){
|
| + while( nIn>0 ){
|
| + int len = 0;
|
| + for(i=0; i<nChar; i++){
|
| + len = aLen[i];
|
| + if( len<=nIn && memcmp(zIn, azChar[i], len)==0 ) break;
|
| + }
|
| + if( i>=nChar ) break;
|
| + zIn += len;
|
| + nIn -= len;
|
| + }
|
| + }
|
| + if( flags & 2 ){
|
| + while( nIn>0 ){
|
| + int len = 0;
|
| + for(i=0; i<nChar; i++){
|
| + len = aLen[i];
|
| + if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break;
|
| + }
|
| + if( i>=nChar ) break;
|
| + nIn -= len;
|
| + }
|
| + }
|
| + if( zCharSet ){
|
| + sqlite3_free(azChar);
|
| + }
|
| + }
|
| + sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
|
| +}
|
| +
|
| +
|
| +/* IMP: R-25361-16150 This function is omitted from SQLite by default. It
|
| +** is only available if the SQLITE_SOUNDEX compile-time option is used
|
| +** when SQLite is built.
|
| +*/
|
| +#ifdef SQLITE_SOUNDEX
|
| +/*
|
| +** Compute the soundex encoding of a word.
|
| +**
|
| +** IMP: R-59782-00072 The soundex(X) function returns a string that is the
|
| +** soundex encoding of the string X.
|
| +*/
|
| +static void soundexFunc(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + char zResult[8];
|
| + const u8 *zIn;
|
| + int i, j;
|
| + static const unsigned char iCode[] = {
|
| + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| + 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
|
| + 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
|
| + 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
|
| + 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
|
| + };
|
| + assert( argc==1 );
|
| + zIn = (u8*)sqlite3_value_text(argv[0]);
|
| + if( zIn==0 ) zIn = (u8*)"";
|
| + for(i=0; zIn[i] && !sqlite3Isalpha(zIn[i]); i++){}
|
| + if( zIn[i] ){
|
| + u8 prevcode = iCode[zIn[i]&0x7f];
|
| + zResult[0] = sqlite3Toupper(zIn[i]);
|
| + for(j=1; j<4 && zIn[i]; i++){
|
| + int code = iCode[zIn[i]&0x7f];
|
| + if( code>0 ){
|
| + if( code!=prevcode ){
|
| + prevcode = code;
|
| + zResult[j++] = code + '0';
|
| + }
|
| + }else{
|
| + prevcode = 0;
|
| + }
|
| + }
|
| + while( j<4 ){
|
| + zResult[j++] = '0';
|
| + }
|
| + zResult[j] = 0;
|
| + sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT);
|
| + }else{
|
| + /* IMP: R-64894-50321 The string "?000" is returned if the argument
|
| + ** is NULL or contains no ASCII alphabetic characters. */
|
| + sqlite3_result_text(context, "?000", 4, SQLITE_STATIC);
|
| + }
|
| +}
|
| +#endif /* SQLITE_SOUNDEX */
|
| +
|
| +#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
| +/*
|
| +** A function that loads a shared-library extension then returns NULL.
|
| +*/
|
| +static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
|
| + const char *zFile = (const char *)sqlite3_value_text(argv[0]);
|
| + const char *zProc;
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + char *zErrMsg = 0;
|
| +
|
| + if( argc==2 ){
|
| + zProc = (const char *)sqlite3_value_text(argv[1]);
|
| + }else{
|
| + zProc = 0;
|
| + }
|
| + if( zFile && sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){
|
| + sqlite3_result_error(context, zErrMsg, -1);
|
| + sqlite3_free(zErrMsg);
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** An instance of the following structure holds the context of a
|
| +** sum() or avg() aggregate computation.
|
| +*/
|
| +typedef struct SumCtx SumCtx;
|
| +struct SumCtx {
|
| + double rSum; /* Floating point sum */
|
| + i64 iSum; /* Integer sum */
|
| + i64 cnt; /* Number of elements summed */
|
| + u8 overflow; /* True if integer overflow seen */
|
| + u8 approx; /* True if non-integer value was input to the sum */
|
| +};
|
| +
|
| +/*
|
| +** Routines used to compute the sum, average, and total.
|
| +**
|
| +** The SUM() function follows the (broken) SQL standard which means
|
| +** that it returns NULL if it sums over no inputs. TOTAL returns
|
| +** 0.0 in that case. In addition, TOTAL always returns a float where
|
| +** SUM might return an integer if it never encounters a floating point
|
| +** value. TOTAL never fails, but SUM might through an exception if
|
| +** it overflows an integer.
|
| +*/
|
| +static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
| + SumCtx *p;
|
| + int type;
|
| + assert( argc==1 );
|
| + UNUSED_PARAMETER(argc);
|
| + p = sqlite3_aggregate_context(context, sizeof(*p));
|
| + type = sqlite3_value_numeric_type(argv[0]);
|
| + if( p && type!=SQLITE_NULL ){
|
| + p->cnt++;
|
| + if( type==SQLITE_INTEGER ){
|
| + i64 v = sqlite3_value_int64(argv[0]);
|
| + p->rSum += v;
|
| + if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
|
| + p->overflow = 1;
|
| + }
|
| + }else{
|
| + p->rSum += sqlite3_value_double(argv[0]);
|
| + p->approx = 1;
|
| + }
|
| + }
|
| +}
|
| +static void sumFinalize(sqlite3_context *context){
|
| + SumCtx *p;
|
| + p = sqlite3_aggregate_context(context, 0);
|
| + if( p && p->cnt>0 ){
|
| + if( p->overflow ){
|
| + sqlite3_result_error(context,"integer overflow",-1);
|
| + }else if( p->approx ){
|
| + sqlite3_result_double(context, p->rSum);
|
| + }else{
|
| + sqlite3_result_int64(context, p->iSum);
|
| + }
|
| + }
|
| +}
|
| +static void avgFinalize(sqlite3_context *context){
|
| + SumCtx *p;
|
| + p = sqlite3_aggregate_context(context, 0);
|
| + if( p && p->cnt>0 ){
|
| + sqlite3_result_double(context, p->rSum/(double)p->cnt);
|
| + }
|
| +}
|
| +static void totalFinalize(sqlite3_context *context){
|
| + SumCtx *p;
|
| + p = sqlite3_aggregate_context(context, 0);
|
| + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
| + sqlite3_result_double(context, p ? p->rSum : (double)0);
|
| +}
|
| +
|
| +/*
|
| +** The following structure keeps track of state information for the
|
| +** count() aggregate function.
|
| +*/
|
| +typedef struct CountCtx CountCtx;
|
| +struct CountCtx {
|
| + i64 n;
|
| +};
|
| +
|
| +/*
|
| +** Routines to implement the count() aggregate function.
|
| +*/
|
| +static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
| + CountCtx *p;
|
| + p = sqlite3_aggregate_context(context, sizeof(*p));
|
| + if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){
|
| + p->n++;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| + /* The sqlite3_aggregate_count() function is deprecated. But just to make
|
| + ** sure it still operates correctly, verify that its count agrees with our
|
| + ** internal count when using count(*) and when the total count can be
|
| + ** expressed as a 32-bit integer. */
|
| + assert( argc==1 || p==0 || p->n>0x7fffffff
|
| + || p->n==sqlite3_aggregate_count(context) );
|
| +#endif
|
| +}
|
| +static void countFinalize(sqlite3_context *context){
|
| + CountCtx *p;
|
| + p = sqlite3_aggregate_context(context, 0);
|
| + sqlite3_result_int64(context, p ? p->n : 0);
|
| +}
|
| +
|
| +/*
|
| +** Routines to implement min() and max() aggregate functions.
|
| +*/
|
| +static void minmaxStep(
|
| + sqlite3_context *context,
|
| + int NotUsed,
|
| + sqlite3_value **argv
|
| +){
|
| + Mem *pArg = (Mem *)argv[0];
|
| + Mem *pBest;
|
| + UNUSED_PARAMETER(NotUsed);
|
| +
|
| + pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
|
| + if( !pBest ) return;
|
| +
|
| + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
|
| + if( pBest->flags ) sqlite3SkipAccumulatorLoad(context);
|
| + }else if( pBest->flags ){
|
| + int max;
|
| + int cmp;
|
| + CollSeq *pColl = sqlite3GetFuncCollSeq(context);
|
| + /* This step function is used for both the min() and max() aggregates,
|
| + ** the only difference between the two being that the sense of the
|
| + ** comparison is inverted. For the max() aggregate, the
|
| + ** sqlite3_user_data() function returns (void *)-1. For min() it
|
| + ** returns (void *)db, where db is the sqlite3* database pointer.
|
| + ** Therefore the next statement sets variable 'max' to 1 for the max()
|
| + ** aggregate, or 0 for min().
|
| + */
|
| + max = sqlite3_user_data(context)!=0;
|
| + cmp = sqlite3MemCompare(pBest, pArg, pColl);
|
| + if( (max && cmp<0) || (!max && cmp>0) ){
|
| + sqlite3VdbeMemCopy(pBest, pArg);
|
| + }else{
|
| + sqlite3SkipAccumulatorLoad(context);
|
| + }
|
| + }else{
|
| + pBest->db = sqlite3_context_db_handle(context);
|
| + sqlite3VdbeMemCopy(pBest, pArg);
|
| + }
|
| +}
|
| +static void minMaxFinalize(sqlite3_context *context){
|
| + sqlite3_value *pRes;
|
| + pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
|
| + if( pRes ){
|
| + if( pRes->flags ){
|
| + sqlite3_result_value(context, pRes);
|
| + }
|
| + sqlite3VdbeMemRelease(pRes);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** group_concat(EXPR, ?SEPARATOR?)
|
| +*/
|
| +static void groupConcatStep(
|
| + sqlite3_context *context,
|
| + int argc,
|
| + sqlite3_value **argv
|
| +){
|
| + const char *zVal;
|
| + StrAccum *pAccum;
|
| + const char *zSep;
|
| + int nVal, nSep;
|
| + assert( argc==1 || argc==2 );
|
| + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
| + pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
|
| +
|
| + if( pAccum ){
|
| + sqlite3 *db = sqlite3_context_db_handle(context);
|
| + int firstTerm = pAccum->mxAlloc==0;
|
| + pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
|
| + if( !firstTerm ){
|
| + if( argc==2 ){
|
| + zSep = (char*)sqlite3_value_text(argv[1]);
|
| + nSep = sqlite3_value_bytes(argv[1]);
|
| + }else{
|
| + zSep = ",";
|
| + nSep = 1;
|
| + }
|
| + if( nSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
|
| + }
|
| + zVal = (char*)sqlite3_value_text(argv[0]);
|
| + nVal = sqlite3_value_bytes(argv[0]);
|
| + if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal);
|
| + }
|
| +}
|
| +static void groupConcatFinalize(sqlite3_context *context){
|
| + StrAccum *pAccum;
|
| + pAccum = sqlite3_aggregate_context(context, 0);
|
| + if( pAccum ){
|
| + if( pAccum->accError==STRACCUM_TOOBIG ){
|
| + sqlite3_result_error_toobig(context);
|
| + }else if( pAccum->accError==STRACCUM_NOMEM ){
|
| + sqlite3_result_error_nomem(context);
|
| + }else{
|
| + sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
|
| + sqlite3_free);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This routine does per-connection function registration. Most
|
| +** of the built-in functions above are part of the global function set.
|
| +** This routine only deals with those that are not global.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
| + int rc = sqlite3_overload_function(db, "MATCH", 2);
|
| + assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
|
| + if( rc==SQLITE_NOMEM ){
|
| + db->mallocFailed = 1;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Set the LIKEOPT flag on the 2-argument function with the given name.
|
| +*/
|
| +static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
|
| + FuncDef *pDef;
|
| + pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
|
| + 2, SQLITE_UTF8, 0);
|
| + if( ALWAYS(pDef) ){
|
| + pDef->funcFlags |= flagVal;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Register the built-in LIKE and GLOB functions. The caseSensitive
|
| +** parameter determines whether or not the LIKE operator is case
|
| +** sensitive. GLOB is always case sensitive.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
| + struct compareInfo *pInfo;
|
| + if( caseSensitive ){
|
| + pInfo = (struct compareInfo*)&likeInfoAlt;
|
| + }else{
|
| + pInfo = (struct compareInfo*)&likeInfoNorm;
|
| + }
|
| + sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
|
| + sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
|
| + sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
|
| + (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
|
| + setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
|
| + setLikeOptFlag(db, "like",
|
| + caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
|
| +}
|
| +
|
| +/*
|
| +** pExpr points to an expression which implements a function. If
|
| +** it is appropriate to apply the LIKE optimization to that function
|
| +** then set aWc[0] through aWc[2] to the wildcard characters and
|
| +** return TRUE. If the function is not a LIKE-style function then
|
| +** return FALSE.
|
| +**
|
| +** *pIsNocase is set to true if uppercase and lowercase are equivalent for
|
| +** the function (default for LIKE). If the function makes the distinction
|
| +** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to
|
| +** false.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
| + FuncDef *pDef;
|
| + if( pExpr->op!=TK_FUNCTION
|
| + || !pExpr->x.pList
|
| + || pExpr->x.pList->nExpr!=2
|
| + ){
|
| + return 0;
|
| + }
|
| + assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
| + pDef = sqlite3FindFunction(db, pExpr->u.zToken,
|
| + sqlite3Strlen30(pExpr->u.zToken),
|
| + 2, SQLITE_UTF8, 0);
|
| + if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
|
| + return 0;
|
| + }
|
| +
|
| + /* The memcpy() statement assumes that the wildcard characters are
|
| + ** the first three statements in the compareInfo structure. The
|
| + ** asserts() that follow verify that assumption
|
| + */
|
| + memcpy(aWc, pDef->pUserData, 3);
|
| + assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
|
| + assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
|
| + assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
|
| + *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0;
|
| + return 1;
|
| +}
|
| +
|
| +/*
|
| +** All of the FuncDef structures in the aBuiltinFunc[] array above
|
| +** to the global function hash table. This occurs at start-time (as
|
| +** a consequence of calling sqlite3_initialize()).
|
| +**
|
| +** After this routine runs
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
|
| + /*
|
| + ** The following array holds FuncDef structures for all of the functions
|
| + ** defined in this file.
|
| + **
|
| + ** The array cannot be constant since changes are made to the
|
| + ** FuncDef.pHash elements at start-time. The elements of this array
|
| + ** are read-only after initialization is complete.
|
| + */
|
| + static SQLITE_WSD FuncDef aBuiltinFunc[] = {
|
| + FUNCTION(ltrim, 1, 1, 0, trimFunc ),
|
| + FUNCTION(ltrim, 2, 1, 0, trimFunc ),
|
| + FUNCTION(rtrim, 1, 2, 0, trimFunc ),
|
| + FUNCTION(rtrim, 2, 2, 0, trimFunc ),
|
| + FUNCTION(trim, 1, 3, 0, trimFunc ),
|
| + FUNCTION(trim, 2, 3, 0, trimFunc ),
|
| + FUNCTION(min, -1, 0, 1, minmaxFunc ),
|
| + FUNCTION(min, 0, 0, 1, 0 ),
|
| + AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize,
|
| + SQLITE_FUNC_MINMAX ),
|
| + FUNCTION(max, -1, 1, 1, minmaxFunc ),
|
| + FUNCTION(max, 0, 1, 1, 0 ),
|
| + AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize,
|
| + SQLITE_FUNC_MINMAX ),
|
| + FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
|
| + FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
|
| + FUNCTION(instr, 2, 0, 0, instrFunc ),
|
| + FUNCTION(substr, 2, 0, 0, substrFunc ),
|
| + FUNCTION(substr, 3, 0, 0, substrFunc ),
|
| + FUNCTION(printf, -1, 0, 0, printfFunc ),
|
| + FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
|
| + FUNCTION(char, -1, 0, 0, charFunc ),
|
| + FUNCTION(abs, 1, 0, 0, absFunc ),
|
| +#ifndef SQLITE_OMIT_FLOATING_POINT
|
| + FUNCTION(round, 1, 0, 0, roundFunc ),
|
| + FUNCTION(round, 2, 0, 0, roundFunc ),
|
| +#endif
|
| + FUNCTION(upper, 1, 0, 0, upperFunc ),
|
| + FUNCTION(lower, 1, 0, 0, lowerFunc ),
|
| + FUNCTION(coalesce, 1, 0, 0, 0 ),
|
| + FUNCTION(coalesce, 0, 0, 0, 0 ),
|
| + FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
|
| + FUNCTION(hex, 1, 0, 0, hexFunc ),
|
| + FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
|
| + FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
| + FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
| + FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
| + VFUNCTION(random, 0, 0, 0, randomFunc ),
|
| + VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
|
| + FUNCTION(nullif, 2, 0, 1, nullifFunc ),
|
| + DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
|
| + DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
|
| + FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
|
| +#if SQLITE_USER_AUTHENTICATION
|
| + FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
|
| +#endif
|
| +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
| + DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
|
| + DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
|
| +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
| + FUNCTION(quote, 1, 0, 0, quoteFunc ),
|
| + VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
|
| + VFUNCTION(changes, 0, 0, 0, changes ),
|
| + VFUNCTION(total_changes, 0, 0, 0, total_changes ),
|
| + FUNCTION(replace, 3, 0, 0, replaceFunc ),
|
| + FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
|
| + #ifdef SQLITE_SOUNDEX
|
| + FUNCTION(soundex, 1, 0, 0, soundexFunc ),
|
| + #endif
|
| + #ifndef SQLITE_OMIT_LOAD_EXTENSION
|
| + VFUNCTION(load_extension, 1, 0, 0, loadExt ),
|
| + VFUNCTION(load_extension, 2, 0, 0, loadExt ),
|
| + #endif
|
| + AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
|
| + AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
|
| + AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
|
| + AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
|
| + SQLITE_FUNC_COUNT ),
|
| + AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
|
| + AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
|
| + AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
|
| +
|
| + LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
|
| + #ifdef SQLITE_CASE_SENSITIVE_LIKE
|
| + LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
|
| + LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
|
| + #else
|
| + LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
|
| + LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
|
| + #endif
|
| + };
|
| +
|
| + int i;
|
| + FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
|
| + FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc);
|
| +
|
| + for(i=0; i<ArraySize(aBuiltinFunc); i++){
|
| + sqlite3FuncDefInsert(pHash, &aFunc[i]);
|
| + }
|
| + sqlite3RegisterDateTimeFunctions();
|
| +#ifndef SQLITE_OMIT_ALTERTABLE
|
| + sqlite3AlterFunctions();
|
| +#endif
|
| +#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
|
| + sqlite3AnalyzeFunctions();
|
| +#endif
|
| +}
|
| +
|
| +/************** End of func.c ************************************************/
|
| +/************** Begin file fkey.c ********************************************/
|
| +/*
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains code used by the compiler to add foreign key
|
| +** support to compiled SQL statements.
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| +#ifndef SQLITE_OMIT_TRIGGER
|
| +
|
| +/*
|
| +** Deferred and Immediate FKs
|
| +** --------------------------
|
| +**
|
| +** Foreign keys in SQLite come in two flavours: deferred and immediate.
|
| +** If an immediate foreign key constraint is violated,
|
| +** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current
|
| +** statement transaction rolled back. If a
|
| +** deferred foreign key constraint is violated, no action is taken
|
| +** immediately. However if the application attempts to commit the
|
| +** transaction before fixing the constraint violation, the attempt fails.
|
| +**
|
| +** Deferred constraints are implemented using a simple counter associated
|
| +** with the database handle. The counter is set to zero each time a
|
| +** database transaction is opened. Each time a statement is executed
|
| +** that causes a foreign key violation, the counter is incremented. Each
|
| +** time a statement is executed that removes an existing violation from
|
| +** the database, the counter is decremented. When the transaction is
|
| +** committed, the commit fails if the current value of the counter is
|
| +** greater than zero. This scheme has two big drawbacks:
|
| +**
|
| +** * When a commit fails due to a deferred foreign key constraint,
|
| +** there is no way to tell which foreign constraint is not satisfied,
|
| +** or which row it is not satisfied for.
|
| +**
|
| +** * If the database contains foreign key violations when the
|
| +** transaction is opened, this may cause the mechanism to malfunction.
|
| +**
|
| +** Despite these problems, this approach is adopted as it seems simpler
|
| +** than the alternatives.
|
| +**
|
| +** INSERT operations:
|
| +**
|
| +** I.1) For each FK for which the table is the child table, search
|
| +** the parent table for a match. If none is found increment the
|
| +** constraint counter.
|
| +**
|
| +** I.2) For each FK for which the table is the parent table,
|
| +** search the child table for rows that correspond to the new
|
| +** row in the parent table. Decrement the counter for each row
|
| +** found (as the constraint is now satisfied).
|
| +**
|
| +** DELETE operations:
|
| +**
|
| +** D.1) For each FK for which the table is the child table,
|
| +** search the parent table for a row that corresponds to the
|
| +** deleted row in the child table. If such a row is not found,
|
| +** decrement the counter.
|
| +**
|
| +** D.2) For each FK for which the table is the parent table, search
|
| +** the child table for rows that correspond to the deleted row
|
| +** in the parent table. For each found increment the counter.
|
| +**
|
| +** UPDATE operations:
|
| +**
|
| +** An UPDATE command requires that all 4 steps above are taken, but only
|
| +** for FK constraints for which the affected columns are actually
|
| +** modified (values must be compared at runtime).
|
| +**
|
| +** Note that I.1 and D.1 are very similar operations, as are I.2 and D.2.
|
| +** This simplifies the implementation a bit.
|
| +**
|
| +** For the purposes of immediate FK constraints, the OR REPLACE conflict
|
| +** resolution is considered to delete rows before the new row is inserted.
|
| +** If a delete caused by OR REPLACE violates an FK constraint, an exception
|
| +** is thrown, even if the FK constraint would be satisfied after the new
|
| +** row is inserted.
|
| +**
|
| +** Immediate constraints are usually handled similarly. The only difference
|
| +** is that the counter used is stored as part of each individual statement
|
| +** object (struct Vdbe). If, after the statement has run, its immediate
|
| +** constraint counter is greater than zero,
|
| +** it returns SQLITE_CONSTRAINT_FOREIGNKEY
|
| +** and the statement transaction is rolled back. An exception is an INSERT
|
| +** statement that inserts a single row only (no triggers). In this case,
|
| +** instead of using a counter, an exception is thrown immediately if the
|
| +** INSERT violates a foreign key constraint. This is necessary as such
|
| +** an INSERT does not open a statement transaction.
|
| +**
|
| +** TODO: How should dropping a table be handled? How should renaming a
|
| +** table be handled?
|
| +**
|
| +**
|
| +** Query API Notes
|
| +** ---------------
|
| +**
|
| +** Before coding an UPDATE or DELETE row operation, the code-generator
|
| +** for those two operations needs to know whether or not the operation
|
| +** requires any FK processing and, if so, which columns of the original
|
| +** row are required by the FK processing VDBE code (i.e. if FKs were
|
| +** implemented using triggers, which of the old.* columns would be
|
| +** accessed). No information is required by the code-generator before
|
| +** coding an INSERT operation. The functions used by the UPDATE/DELETE
|
| +** generation code to query for this information are:
|
| +**
|
| +** sqlite3FkRequired() - Test to see if FK processing is required.
|
| +** sqlite3FkOldmask() - Query for the set of required old.* columns.
|
| +**
|
| +**
|
| +** Externally accessible module functions
|
| +** --------------------------------------
|
| +**
|
| +** sqlite3FkCheck() - Check for foreign key violations.
|
| +** sqlite3FkActions() - Code triggers for ON UPDATE/ON DELETE actions.
|
| +** sqlite3FkDelete() - Delete an FKey structure.
|
| +*/
|
| +
|
| +/*
|
| +** VDBE Calling Convention
|
| +** -----------------------
|
| +**
|
| +** Example:
|
| +**
|
| +** For the following INSERT statement:
|
| +**
|
| +** CREATE TABLE t1(a, b INTEGER PRIMARY KEY, c);
|
| +** INSERT INTO t1 VALUES(1, 2, 3.1);
|
| +**
|
| +** Register (x): 2 (type integer)
|
| +** Register (x+1): 1 (type integer)
|
| +** Register (x+2): NULL (type NULL)
|
| +** Register (x+3): 3.1 (type real)
|
| +*/
|
| +
|
| +/*
|
| +** A foreign key constraint requires that the key columns in the parent
|
| +** table are collectively subject to a UNIQUE or PRIMARY KEY constraint.
|
| +** Given that pParent is the parent table for foreign key constraint pFKey,
|
| +** search the schema for a unique index on the parent key columns.
|
| +**
|
| +** If successful, zero is returned. If the parent key is an INTEGER PRIMARY
|
| +** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx
|
| +** is set to point to the unique index.
|
| +**
|
| +** If the parent key consists of a single column (the foreign key constraint
|
| +** is not a composite foreign key), output variable *paiCol is set to NULL.
|
| +** Otherwise, it is set to point to an allocated array of size N, where
|
| +** N is the number of columns in the parent key. The first element of the
|
| +** array is the index of the child table column that is mapped by the FK
|
| +** constraint to the parent table column stored in the left-most column
|
| +** of index *ppIdx. The second element of the array is the index of the
|
| +** child table column that corresponds to the second left-most column of
|
| +** *ppIdx, and so on.
|
| +**
|
| +** If the required index cannot be found, either because:
|
| +**
|
| +** 1) The named parent key columns do not exist, or
|
| +**
|
| +** 2) The named parent key columns do exist, but are not subject to a
|
| +** UNIQUE or PRIMARY KEY constraint, or
|
| +**
|
| +** 3) No parent key columns were provided explicitly as part of the
|
| +** foreign key definition, and the parent table does not have a
|
| +** PRIMARY KEY, or
|
| +**
|
| +** 4) No parent key columns were provided explicitly as part of the
|
| +** foreign key definition, and the PRIMARY KEY of the parent table
|
| +** consists of a different number of columns to the child key in
|
| +** the child table.
|
| +**
|
| +** then non-zero is returned, and a "foreign key mismatch" error loaded
|
| +** into pParse. If an OOM error occurs, non-zero is returned and the
|
| +** pParse->db->mallocFailed flag is set.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3FkLocateIndex(
|
| + Parse *pParse, /* Parse context to store any error in */
|
| + Table *pParent, /* Parent table of FK constraint pFKey */
|
| + FKey *pFKey, /* Foreign key to find index for */
|
| + Index **ppIdx, /* OUT: Unique index on parent table */
|
| + int **paiCol /* OUT: Map of index columns in pFKey */
|
| +){
|
| + Index *pIdx = 0; /* Value to return via *ppIdx */
|
| + int *aiCol = 0; /* Value to return via *paiCol */
|
| + int nCol = pFKey->nCol; /* Number of columns in parent key */
|
| + char *zKey = pFKey->aCol[0].zCol; /* Name of left-most parent key column */
|
| +
|
| + /* The caller is responsible for zeroing output parameters. */
|
| + assert( ppIdx && *ppIdx==0 );
|
| + assert( !paiCol || *paiCol==0 );
|
| + assert( pParse );
|
| +
|
| + /* If this is a non-composite (single column) foreign key, check if it
|
| + ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx
|
| + ** and *paiCol set to zero and return early.
|
| + **
|
| + ** Otherwise, for a composite foreign key (more than one column), allocate
|
| + ** space for the aiCol array (returned via output parameter *paiCol).
|
| + ** Non-composite foreign keys do not require the aiCol array.
|
| + */
|
| + if( nCol==1 ){
|
| + /* The FK maps to the IPK if any of the following are true:
|
| + **
|
| + ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly
|
| + ** mapped to the primary key of table pParent, or
|
| + ** 2) The FK is explicitly mapped to a column declared as INTEGER
|
| + ** PRIMARY KEY.
|
| + */
|
| + if( pParent->iPKey>=0 ){
|
| + if( !zKey ) return 0;
|
| + if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zName, zKey) ) return 0;
|
| + }
|
| + }else if( paiCol ){
|
| + assert( nCol>1 );
|
| + aiCol = (int *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int));
|
| + if( !aiCol ) return 1;
|
| + *paiCol = aiCol;
|
| + }
|
| +
|
| + for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){
|
| + /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number
|
| + ** of columns. If each indexed column corresponds to a foreign key
|
| + ** column of pFKey, then this index is a winner. */
|
| +
|
| + if( zKey==0 ){
|
| + /* If zKey is NULL, then this foreign key is implicitly mapped to
|
| + ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be
|
| + ** identified by the test. */
|
| + if( IsPrimaryKeyIndex(pIdx) ){
|
| + if( aiCol ){
|
| + int i;
|
| + for(i=0; i<nCol; i++) aiCol[i] = pFKey->aCol[i].iFrom;
|
| + }
|
| + break;
|
| + }
|
| + }else{
|
| + /* If zKey is non-NULL, then this foreign key was declared to
|
| + ** map to an explicit list of columns in table pParent. Check if this
|
| + ** index matches those columns. Also, check that the index uses
|
| + ** the default collation sequences for each column. */
|
| + int i, j;
|
| + for(i=0; i<nCol; i++){
|
| + i16 iCol = pIdx->aiColumn[i]; /* Index of column in parent tbl */
|
| + const char *zDfltColl; /* Def. collation for column */
|
| + char *zIdxCol; /* Name of indexed column */
|
| +
|
| + if( iCol<0 ) break; /* No foreign keys against expression indexes */
|
| +
|
| + /* If the index uses a collation sequence that is different from
|
| + ** the default collation sequence for the column, this index is
|
| + ** unusable. Bail out early in this case. */
|
| + zDfltColl = pParent->aCol[iCol].zColl;
|
| + if( !zDfltColl ) zDfltColl = sqlite3StrBINARY;
|
| + if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break;
|
| +
|
| + zIdxCol = pParent->aCol[iCol].zName;
|
| + for(j=0; j<nCol; j++){
|
| + if( sqlite3StrICmp(pFKey->aCol[j].zCol, zIdxCol)==0 ){
|
| + if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom;
|
| + break;
|
| + }
|
| + }
|
| + if( j==nCol ) break;
|
| + }
|
| + if( i==nCol ) break; /* pIdx is usable */
|
| + }
|
| + }
|
| + }
|
| +
|
| + if( !pIdx ){
|
| + if( !pParse->disableTriggers ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "foreign key mismatch - \"%w\" referencing \"%w\"",
|
| + pFKey->pFrom->zName, pFKey->zTo);
|
| + }
|
| + sqlite3DbFree(pParse->db, aiCol);
|
| + return 1;
|
| + }
|
| +
|
| + *ppIdx = pIdx;
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** This function is called when a row is inserted into or deleted from the
|
| +** child table of foreign key constraint pFKey. If an SQL UPDATE is executed
|
| +** on the child table of pFKey, this function is invoked twice for each row
|
| +** affected - once to "delete" the old row, and then again to "insert" the
|
| +** new row.
|
| +**
|
| +** Each time it is called, this function generates VDBE code to locate the
|
| +** row in the parent table that corresponds to the row being inserted into
|
| +** or deleted from the child table. If the parent row can be found, no
|
| +** special action is taken. Otherwise, if the parent row can *not* be
|
| +** found in the parent table:
|
| +**
|
| +** Operation | FK type | Action taken
|
| +** --------------------------------------------------------------------------
|
| +** INSERT immediate Increment the "immediate constraint counter".
|
| +**
|
| +** DELETE immediate Decrement the "immediate constraint counter".
|
| +**
|
| +** INSERT deferred Increment the "deferred constraint counter".
|
| +**
|
| +** DELETE deferred Decrement the "deferred constraint counter".
|
| +**
|
| +** These operations are identified in the comment at the top of this file
|
| +** (fkey.c) as "I.1" and "D.1".
|
| +*/
|
| +static void fkLookupParent(
|
| + Parse *pParse, /* Parse context */
|
| + int iDb, /* Index of database housing pTab */
|
| + Table *pTab, /* Parent table of FK pFKey */
|
| + Index *pIdx, /* Unique index on parent key columns in pTab */
|
| + FKey *pFKey, /* Foreign key constraint */
|
| + int *aiCol, /* Map from parent key columns to child table columns */
|
| + int regData, /* Address of array containing child table row */
|
| + int nIncr, /* Increment constraint counter by this */
|
| + int isIgnore /* If true, pretend pTab contains all NULL values */
|
| +){
|
| + int i; /* Iterator variable */
|
| + Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */
|
| + int iCur = pParse->nTab - 1; /* Cursor number to use */
|
| + int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */
|
| +
|
| + /* If nIncr is less than zero, then check at runtime if there are any
|
| + ** outstanding constraints to resolve. If there are not, there is no need
|
| + ** to check if deleting this row resolves any outstanding violations.
|
| + **
|
| + ** Check if any of the key columns in the child table row are NULL. If
|
| + ** any are, then the constraint is considered satisfied. No need to
|
| + ** search for a matching row in the parent table. */
|
| + if( nIncr<0 ){
|
| + sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk);
|
| + VdbeCoverage(v);
|
| + }
|
| + for(i=0; i<pFKey->nCol; i++){
|
| + int iReg = aiCol[i] + regData + 1;
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v);
|
| + }
|
| +
|
| + if( isIgnore==0 ){
|
| + if( pIdx==0 ){
|
| + /* If pIdx is NULL, then the parent key is the INTEGER PRIMARY KEY
|
| + ** column of the parent table (table pTab). */
|
| + int iMustBeInt; /* Address of MustBeInt instruction */
|
| + int regTemp = sqlite3GetTempReg(pParse);
|
| +
|
| + /* Invoke MustBeInt to coerce the child key value to an integer (i.e.
|
| + ** apply the affinity of the parent key). If this fails, then there
|
| + ** is no matching parent key. Before using MustBeInt, make a copy of
|
| + ** the value. Otherwise, the value inserted into the child key column
|
| + ** will have INTEGER affinity applied to it, which may not be correct. */
|
| + sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp);
|
| + iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0);
|
| + VdbeCoverage(v);
|
| +
|
| + /* If the parent table is the same as the child table, and we are about
|
| + ** to increment the constraint-counter (i.e. this is an INSERT operation),
|
| + ** then check if the row being inserted matches itself. If so, do not
|
| + ** increment the constraint-counter. */
|
| + if( pTab==pFKey->pFrom && nIncr==1 ){
|
| + sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); VdbeCoverage(v);
|
| + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
| + }
|
| +
|
| + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
|
| + sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v);
|
| + sqlite3VdbeGoto(v, iOk);
|
| + sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
| + sqlite3VdbeJumpHere(v, iMustBeInt);
|
| + sqlite3ReleaseTempReg(pParse, regTemp);
|
| + }else{
|
| + int nCol = pFKey->nCol;
|
| + int regTemp = sqlite3GetTempRange(pParse, nCol);
|
| + int regRec = sqlite3GetTempReg(pParse);
|
| +
|
| + sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
|
| + sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
| + for(i=0; i<nCol; i++){
|
| + sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
|
| + }
|
| +
|
| + /* If the parent table is the same as the child table, and we are about
|
| + ** to increment the constraint-counter (i.e. this is an INSERT operation),
|
| + ** then check if the row being inserted matches itself. If so, do not
|
| + ** increment the constraint-counter.
|
| + **
|
| + ** If any of the parent-key values are NULL, then the row cannot match
|
| + ** itself. So set JUMPIFNULL to make sure we do the OP_Found if any
|
| + ** of the parent-key values are NULL (at this point it is known that
|
| + ** none of the child key values are).
|
| + */
|
| + if( pTab==pFKey->pFrom && nIncr==1 ){
|
| + int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1;
|
| + for(i=0; i<nCol; i++){
|
| + int iChild = aiCol[i]+1+regData;
|
| + int iParent = pIdx->aiColumn[i]+1+regData;
|
| + assert( pIdx->aiColumn[i]>=0 );
|
| + assert( aiCol[i]!=pTab->iPKey );
|
| + if( pIdx->aiColumn[i]==pTab->iPKey ){
|
| + /* The parent key is a composite key that includes the IPK column */
|
| + iParent = regData;
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v);
|
| + sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
| + }
|
| + sqlite3VdbeGoto(v, iOk);
|
| + }
|
| +
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec,
|
| + sqlite3IndexAffinityStr(pParse->db,pIdx), nCol);
|
| + sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v);
|
| +
|
| + sqlite3ReleaseTempReg(pParse, regRec);
|
| + sqlite3ReleaseTempRange(pParse, regTemp, nCol);
|
| + }
|
| + }
|
| +
|
| + if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs)
|
| + && !pParse->pToplevel
|
| + && !pParse->isMultiWrite
|
| + ){
|
| + /* Special case: If this is an INSERT statement that will insert exactly
|
| + ** one row into the table, raise a constraint immediately instead of
|
| + ** incrementing a counter. This is necessary as the VM code is being
|
| + ** generated for will not open a statement transaction. */
|
| + assert( nIncr==1 );
|
| + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
|
| + OE_Abort, 0, P4_STATIC, P5_ConstraintFK);
|
| + }else{
|
| + if( nIncr>0 && pFKey->isDeferred==0 ){
|
| + sqlite3MayAbort(pParse);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
|
| + }
|
| +
|
| + sqlite3VdbeResolveLabel(v, iOk);
|
| + sqlite3VdbeAddOp1(v, OP_Close, iCur);
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Return an Expr object that refers to a memory register corresponding
|
| +** to column iCol of table pTab.
|
| +**
|
| +** regBase is the first of an array of register that contains the data
|
| +** for pTab. regBase itself holds the rowid. regBase+1 holds the first
|
| +** column. regBase+2 holds the second column, and so forth.
|
| +*/
|
| +static Expr *exprTableRegister(
|
| + Parse *pParse, /* Parsing and code generating context */
|
| + Table *pTab, /* The table whose content is at r[regBase]... */
|
| + int regBase, /* Contents of table pTab */
|
| + i16 iCol /* Which column of pTab is desired */
|
| +){
|
| + Expr *pExpr;
|
| + Column *pCol;
|
| + const char *zColl;
|
| + sqlite3 *db = pParse->db;
|
| +
|
| + pExpr = sqlite3Expr(db, TK_REGISTER, 0);
|
| + if( pExpr ){
|
| + if( iCol>=0 && iCol!=pTab->iPKey ){
|
| + pCol = &pTab->aCol[iCol];
|
| + pExpr->iTable = regBase + iCol + 1;
|
| + pExpr->affinity = pCol->affinity;
|
| + zColl = pCol->zColl;
|
| + if( zColl==0 ) zColl = db->pDfltColl->zName;
|
| + pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl);
|
| + }else{
|
| + pExpr->iTable = regBase;
|
| + pExpr->affinity = SQLITE_AFF_INTEGER;
|
| + }
|
| + }
|
| + return pExpr;
|
| +}
|
| +
|
| +/*
|
| +** Return an Expr object that refers to column iCol of table pTab which
|
| +** has cursor iCur.
|
| +*/
|
| +static Expr *exprTableColumn(
|
| + sqlite3 *db, /* The database connection */
|
| + Table *pTab, /* The table whose column is desired */
|
| + int iCursor, /* The open cursor on the table */
|
| + i16 iCol /* The column that is wanted */
|
| +){
|
| + Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0);
|
| + if( pExpr ){
|
| + pExpr->pTab = pTab;
|
| + pExpr->iTable = iCursor;
|
| + pExpr->iColumn = iCol;
|
| + }
|
| + return pExpr;
|
| +}
|
| +
|
| +/*
|
| +** This function is called to generate code executed when a row is deleted
|
| +** from the parent table of foreign key constraint pFKey and, if pFKey is
|
| +** deferred, when a row is inserted into the same table. When generating
|
| +** code for an SQL UPDATE operation, this function may be called twice -
|
| +** once to "delete" the old row and once to "insert" the new row.
|
| +**
|
| +** Parameter nIncr is passed -1 when inserting a row (as this may decrease
|
| +** the number of FK violations in the db) or +1 when deleting one (as this
|
| +** may increase the number of FK constraint problems).
|
| +**
|
| +** The code generated by this function scans through the rows in the child
|
| +** table that correspond to the parent table row being deleted or inserted.
|
| +** For each child row found, one of the following actions is taken:
|
| +**
|
| +** Operation | FK type | Action taken
|
| +** --------------------------------------------------------------------------
|
| +** DELETE immediate Increment the "immediate constraint counter".
|
| +** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
|
| +** throw a "FOREIGN KEY constraint failed" exception.
|
| +**
|
| +** INSERT immediate Decrement the "immediate constraint counter".
|
| +**
|
| +** DELETE deferred Increment the "deferred constraint counter".
|
| +** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
|
| +** throw a "FOREIGN KEY constraint failed" exception.
|
| +**
|
| +** INSERT deferred Decrement the "deferred constraint counter".
|
| +**
|
| +** These operations are identified in the comment at the top of this file
|
| +** (fkey.c) as "I.2" and "D.2".
|
| +*/
|
| +static void fkScanChildren(
|
| + Parse *pParse, /* Parse context */
|
| + SrcList *pSrc, /* The child table to be scanned */
|
| + Table *pTab, /* The parent table */
|
| + Index *pIdx, /* Index on parent covering the foreign key */
|
| + FKey *pFKey, /* The foreign key linking pSrc to pTab */
|
| + int *aiCol, /* Map from pIdx cols to child table cols */
|
| + int regData, /* Parent row data starts here */
|
| + int nIncr /* Amount to increment deferred counter by */
|
| +){
|
| + sqlite3 *db = pParse->db; /* Database handle */
|
| + int i; /* Iterator variable */
|
| + Expr *pWhere = 0; /* WHERE clause to scan with */
|
| + NameContext sNameContext; /* Context used to resolve WHERE clause */
|
| + WhereInfo *pWInfo; /* Context used by sqlite3WhereXXX() */
|
| + int iFkIfZero = 0; /* Address of OP_FkIfZero */
|
| + Vdbe *v = sqlite3GetVdbe(pParse);
|
| +
|
| + assert( pIdx==0 || pIdx->pTable==pTab );
|
| + assert( pIdx==0 || pIdx->nKeyCol==pFKey->nCol );
|
| + assert( pIdx!=0 || pFKey->nCol==1 );
|
| + assert( pIdx!=0 || HasRowid(pTab) );
|
| +
|
| + if( nIncr<0 ){
|
| + iFkIfZero = sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, 0);
|
| + VdbeCoverage(v);
|
| + }
|
| +
|
| + /* Create an Expr object representing an SQL expression like:
|
| + **
|
| + ** <parent-key1> = <child-key1> AND <parent-key2> = <child-key2> ...
|
| + **
|
| + ** The collation sequence used for the comparison should be that of
|
| + ** the parent key columns. The affinity of the parent key column should
|
| + ** be applied to each child key value before the comparison takes place.
|
| + */
|
| + for(i=0; i<pFKey->nCol; i++){
|
| + Expr *pLeft; /* Value from parent table row */
|
| + Expr *pRight; /* Column ref to child table */
|
| + Expr *pEq; /* Expression (pLeft = pRight) */
|
| + i16 iCol; /* Index of column in child table */
|
| + const char *zCol; /* Name of column in child table */
|
| +
|
| + iCol = pIdx ? pIdx->aiColumn[i] : -1;
|
| + pLeft = exprTableRegister(pParse, pTab, regData, iCol);
|
| + iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
|
| + assert( iCol>=0 );
|
| + zCol = pFKey->pFrom->aCol[iCol].zName;
|
| + pRight = sqlite3Expr(db, TK_ID, zCol);
|
| + pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
|
| + pWhere = sqlite3ExprAnd(db, pWhere, pEq);
|
| + }
|
| +
|
| + /* If the child table is the same as the parent table, then add terms
|
| + ** to the WHERE clause that prevent this entry from being scanned.
|
| + ** The added WHERE clause terms are like this:
|
| + **
|
| + ** $current_rowid!=rowid
|
| + ** NOT( $current_a==a AND $current_b==b AND ... )
|
| + **
|
| + ** The first form is used for rowid tables. The second form is used
|
| + ** for WITHOUT ROWID tables. In the second form, the primary key is
|
| + ** (a,b,...)
|
| + */
|
| + if( pTab==pFKey->pFrom && nIncr>0 ){
|
| + Expr *pNe; /* Expression (pLeft != pRight) */
|
| + Expr *pLeft; /* Value from parent table row */
|
| + Expr *pRight; /* Column ref to child table */
|
| + if( HasRowid(pTab) ){
|
| + pLeft = exprTableRegister(pParse, pTab, regData, -1);
|
| + pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1);
|
| + pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0);
|
| + }else{
|
| + Expr *pEq, *pAll = 0;
|
| + Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
| + assert( pIdx!=0 );
|
| + for(i=0; i<pPk->nKeyCol; i++){
|
| + i16 iCol = pIdx->aiColumn[i];
|
| + assert( iCol>=0 );
|
| + pLeft = exprTableRegister(pParse, pTab, regData, iCol);
|
| + pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
|
| + pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
|
| + pAll = sqlite3ExprAnd(db, pAll, pEq);
|
| + }
|
| + pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0, 0);
|
| + }
|
| + pWhere = sqlite3ExprAnd(db, pWhere, pNe);
|
| + }
|
| +
|
| + /* Resolve the references in the WHERE clause. */
|
| + memset(&sNameContext, 0, sizeof(NameContext));
|
| + sNameContext.pSrcList = pSrc;
|
| + sNameContext.pParse = pParse;
|
| + sqlite3ResolveExprNames(&sNameContext, pWhere);
|
| +
|
| + /* Create VDBE to loop through the entries in pSrc that match the WHERE
|
| + ** clause. For each row found, increment either the deferred or immediate
|
| + ** foreign key constraint counter. */
|
| + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
|
| + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
|
| + if( pWInfo ){
|
| + sqlite3WhereEnd(pWInfo);
|
| + }
|
| +
|
| + /* Clean up the WHERE clause constructed above. */
|
| + sqlite3ExprDelete(db, pWhere);
|
| + if( iFkIfZero ){
|
| + sqlite3VdbeJumpHere(v, iFkIfZero);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This function returns a linked list of FKey objects (connected by
|
| +** FKey.pNextTo) holding all children of table pTab. For example,
|
| +** given the following schema:
|
| +**
|
| +** CREATE TABLE t1(a PRIMARY KEY);
|
| +** CREATE TABLE t2(b REFERENCES t1(a);
|
| +**
|
| +** Calling this function with table "t1" as an argument returns a pointer
|
| +** to the FKey structure representing the foreign key constraint on table
|
| +** "t2". Calling this function with "t2" as the argument would return a
|
| +** NULL pointer (as there are no FK constraints for which t2 is the parent
|
| +** table).
|
| +*/
|
| +SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){
|
| + return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName);
|
| +}
|
| +
|
| +/*
|
| +** The second argument is a Trigger structure allocated by the
|
| +** fkActionTrigger() routine. This function deletes the Trigger structure
|
| +** and all of its sub-components.
|
| +**
|
| +** The Trigger structure or any of its sub-components may be allocated from
|
| +** the lookaside buffer belonging to database handle dbMem.
|
| +*/
|
| +static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
|
| + if( p ){
|
| + TriggerStep *pStep = p->step_list;
|
| + sqlite3ExprDelete(dbMem, pStep->pWhere);
|
| + sqlite3ExprListDelete(dbMem, pStep->pExprList);
|
| + sqlite3SelectDelete(dbMem, pStep->pSelect);
|
| + sqlite3ExprDelete(dbMem, p->pWhen);
|
| + sqlite3DbFree(dbMem, p);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This function is called to generate code that runs when table pTab is
|
| +** being dropped from the database. The SrcList passed as the second argument
|
| +** to this function contains a single entry guaranteed to resolve to
|
| +** table pTab.
|
| +**
|
| +** Normally, no code is required. However, if either
|
| +**
|
| +** (a) The table is the parent table of a FK constraint, or
|
| +** (b) The table is the child table of a deferred FK constraint and it is
|
| +** determined at runtime that there are outstanding deferred FK
|
| +** constraint violations in the database,
|
| +**
|
| +** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
|
| +** the table from the database. Triggers are disabled while running this
|
| +** DELETE, but foreign key actions are not.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
| + sqlite3 *db = pParse->db;
|
| + if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) && !pTab->pSelect ){
|
| + int iSkip = 0;
|
| + Vdbe *v = sqlite3GetVdbe(pParse);
|
| +
|
| + assert( v ); /* VDBE has already been allocated */
|
| + if( sqlite3FkReferences(pTab)==0 ){
|
| + /* Search for a deferred foreign key constraint for which this table
|
| + ** is the child table. If one cannot be found, return without
|
| + ** generating any VDBE code. If one can be found, then jump over
|
| + ** the entire DELETE if there are no outstanding deferred constraints
|
| + ** when this statement is run. */
|
| + FKey *p;
|
| + for(p=pTab->pFKey; p; p=p->pNextFrom){
|
| + if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break;
|
| + }
|
| + if( !p ) return;
|
| + iSkip = sqlite3VdbeMakeLabel(v);
|
| + sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v);
|
| + }
|
| +
|
| + pParse->disableTriggers = 1;
|
| + sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0);
|
| + pParse->disableTriggers = 0;
|
| +
|
| + /* If the DELETE has generated immediate foreign key constraint
|
| + ** violations, halt the VDBE and return an error at this point, before
|
| + ** any modifications to the schema are made. This is because statement
|
| + ** transactions are not able to rollback schema changes.
|
| + **
|
| + ** If the SQLITE_DeferFKs flag is set, then this is not required, as
|
| + ** the statement transaction will not be rolled back even if FK
|
| + ** constraints are violated.
|
| + */
|
| + if( (db->flags & SQLITE_DeferFKs)==0 ){
|
| + sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
|
| + VdbeCoverage(v);
|
| + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
|
| + OE_Abort, 0, P4_STATIC, P5_ConstraintFK);
|
| + }
|
| +
|
| + if( iSkip ){
|
| + sqlite3VdbeResolveLabel(v, iSkip);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +/*
|
| +** The second argument points to an FKey object representing a foreign key
|
| +** for which pTab is the child table. An UPDATE statement against pTab
|
| +** is currently being processed. For each column of the table that is
|
| +** actually updated, the corresponding element in the aChange[] array
|
| +** is zero or greater (if a column is unmodified the corresponding element
|
| +** is set to -1). If the rowid column is modified by the UPDATE statement
|
| +** the bChngRowid argument is non-zero.
|
| +**
|
| +** This function returns true if any of the columns that are part of the
|
| +** child key for FK constraint *p are modified.
|
| +*/
|
| +static int fkChildIsModified(
|
| + Table *pTab, /* Table being updated */
|
| + FKey *p, /* Foreign key for which pTab is the child */
|
| + int *aChange, /* Array indicating modified columns */
|
| + int bChngRowid /* True if rowid is modified by this update */
|
| +){
|
| + int i;
|
| + for(i=0; i<p->nCol; i++){
|
| + int iChildKey = p->aCol[i].iFrom;
|
| + if( aChange[iChildKey]>=0 ) return 1;
|
| + if( iChildKey==pTab->iPKey && bChngRowid ) return 1;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** The second argument points to an FKey object representing a foreign key
|
| +** for which pTab is the parent table. An UPDATE statement against pTab
|
| +** is currently being processed. For each column of the table that is
|
| +** actually updated, the corresponding element in the aChange[] array
|
| +** is zero or greater (if a column is unmodified the corresponding element
|
| +** is set to -1). If the rowid column is modified by the UPDATE statement
|
| +** the bChngRowid argument is non-zero.
|
| +**
|
| +** This function returns true if any of the columns that are part of the
|
| +** parent key for FK constraint *p are modified.
|
| +*/
|
| +static int fkParentIsModified(
|
| + Table *pTab,
|
| + FKey *p,
|
| + int *aChange,
|
| + int bChngRowid
|
| +){
|
| + int i;
|
| + for(i=0; i<p->nCol; i++){
|
| + char *zKey = p->aCol[i].zCol;
|
| + int iKey;
|
| + for(iKey=0; iKey<pTab->nCol; iKey++){
|
| + if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){
|
| + Column *pCol = &pTab->aCol[iKey];
|
| + if( zKey ){
|
| + if( 0==sqlite3StrICmp(pCol->zName, zKey) ) return 1;
|
| + }else if( pCol->colFlags & COLFLAG_PRIMKEY ){
|
| + return 1;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** Return true if the parser passed as the first argument is being
|
| +** used to code a trigger that is really a "SET NULL" action belonging
|
| +** to trigger pFKey.
|
| +*/
|
| +static int isSetNullAction(Parse *pParse, FKey *pFKey){
|
| + Parse *pTop = sqlite3ParseToplevel(pParse);
|
| + if( pTop->pTriggerPrg ){
|
| + Trigger *p = pTop->pTriggerPrg->pTrigger;
|
| + if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
|
| + || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
|
| + ){
|
| + return 1;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** This function is called when inserting, deleting or updating a row of
|
| +** table pTab to generate VDBE code to perform foreign key constraint
|
| +** processing for the operation.
|
| +**
|
| +** For a DELETE operation, parameter regOld is passed the index of the
|
| +** first register in an array of (pTab->nCol+1) registers containing the
|
| +** rowid of the row being deleted, followed by each of the column values
|
| +** of the row being deleted, from left to right. Parameter regNew is passed
|
| +** zero in this case.
|
| +**
|
| +** For an INSERT operation, regOld is passed zero and regNew is passed the
|
| +** first register of an array of (pTab->nCol+1) registers containing the new
|
| +** row data.
|
| +**
|
| +** For an UPDATE operation, this function is called twice. Once before
|
| +** the original record is deleted from the table using the calling convention
|
| +** described for DELETE. Then again after the original record is deleted
|
| +** but before the new record is inserted using the INSERT convention.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3FkCheck(
|
| + Parse *pParse, /* Parse context */
|
| + Table *pTab, /* Row is being deleted from this table */
|
| + int regOld, /* Previous row data is stored here */
|
| + int regNew, /* New row data is stored here */
|
| + int *aChange, /* Array indicating UPDATEd columns (or 0) */
|
| + int bChngRowid /* True if rowid is UPDATEd */
|
| +){
|
| + sqlite3 *db = pParse->db; /* Database handle */
|
| + FKey *pFKey; /* Used to iterate through FKs */
|
| + int iDb; /* Index of database containing pTab */
|
| + const char *zDb; /* Name of database containing pTab */
|
| + int isIgnoreErrors = pParse->disableTriggers;
|
| +
|
| + /* Exactly one of regOld and regNew should be non-zero. */
|
| + assert( (regOld==0)!=(regNew==0) );
|
| +
|
| + /* If foreign-keys are disabled, this function is a no-op. */
|
| + if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
|
| +
|
| + iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| + zDb = db->aDb[iDb].zName;
|
| +
|
| + /* Loop through all the foreign key constraints for which pTab is the
|
| + ** child table (the table that the foreign key definition is part of). */
|
| + for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
| + Table *pTo; /* Parent table of foreign key pFKey */
|
| + Index *pIdx = 0; /* Index on key columns in pTo */
|
| + int *aiFree = 0;
|
| + int *aiCol;
|
| + int iCol;
|
| + int i;
|
| + int bIgnore = 0;
|
| +
|
| + if( aChange
|
| + && sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
|
| + && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
|
| + ){
|
| + continue;
|
| + }
|
| +
|
| + /* Find the parent table of this foreign key. Also find a unique index
|
| + ** on the parent key columns in the parent table. If either of these
|
| + ** schema items cannot be located, set an error in pParse and return
|
| + ** early. */
|
| + if( pParse->disableTriggers ){
|
| + pTo = sqlite3FindTable(db, pFKey->zTo, zDb);
|
| + }else{
|
| + pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb);
|
| + }
|
| + if( !pTo || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){
|
| + assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) );
|
| + if( !isIgnoreErrors || db->mallocFailed ) return;
|
| + if( pTo==0 ){
|
| + /* If isIgnoreErrors is true, then a table is being dropped. In this
|
| + ** case SQLite runs a "DELETE FROM xxx" on the table being dropped
|
| + ** before actually dropping it in order to check FK constraints.
|
| + ** If the parent table of an FK constraint on the current table is
|
| + ** missing, behave as if it is empty. i.e. decrement the relevant
|
| + ** FK counter for each row of the current table with non-NULL keys.
|
| + */
|
| + Vdbe *v = sqlite3GetVdbe(pParse);
|
| + int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1;
|
| + for(i=0; i<pFKey->nCol; i++){
|
| + int iReg = pFKey->aCol[i].iFrom + regOld + 1;
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1);
|
| + }
|
| + continue;
|
| + }
|
| + assert( pFKey->nCol==1 || (aiFree && pIdx) );
|
| +
|
| + if( aiFree ){
|
| + aiCol = aiFree;
|
| + }else{
|
| + iCol = pFKey->aCol[0].iFrom;
|
| + aiCol = &iCol;
|
| + }
|
| + for(i=0; i<pFKey->nCol; i++){
|
| + if( aiCol[i]==pTab->iPKey ){
|
| + aiCol[i] = -1;
|
| + }
|
| + assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + /* Request permission to read the parent key columns. If the
|
| + ** authorization callback returns SQLITE_IGNORE, behave as if any
|
| + ** values read from the parent table are NULL. */
|
| + if( db->xAuth ){
|
| + int rcauth;
|
| + char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName;
|
| + rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb);
|
| + bIgnore = (rcauth==SQLITE_IGNORE);
|
| + }
|
| +#endif
|
| + }
|
| +
|
| + /* Take a shared-cache advisory read-lock on the parent table. Allocate
|
| + ** a cursor to use to search the unique index on the parent key columns
|
| + ** in the parent table. */
|
| + sqlite3TableLock(pParse, iDb, pTo->tnum, 0, pTo->zName);
|
| + pParse->nTab++;
|
| +
|
| + if( regOld!=0 ){
|
| + /* A row is being removed from the child table. Search for the parent.
|
| + ** If the parent does not exist, removing the child row resolves an
|
| + ** outstanding foreign key constraint violation. */
|
| + fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore);
|
| + }
|
| + if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){
|
| + /* A row is being added to the child table. If a parent row cannot
|
| + ** be found, adding the child row has violated the FK constraint.
|
| + **
|
| + ** If this operation is being performed as part of a trigger program
|
| + ** that is actually a "SET NULL" action belonging to this very
|
| + ** foreign key, then omit this scan altogether. As all child key
|
| + ** values are guaranteed to be NULL, it is not possible for adding
|
| + ** this row to cause an FK violation. */
|
| + fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore);
|
| + }
|
| +
|
| + sqlite3DbFree(db, aiFree);
|
| + }
|
| +
|
| + /* Loop through all the foreign key constraints that refer to this table.
|
| + ** (the "child" constraints) */
|
| + for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
|
| + Index *pIdx = 0; /* Foreign key index for pFKey */
|
| + SrcList *pSrc;
|
| + int *aiCol = 0;
|
| +
|
| + if( aChange && fkParentIsModified(pTab, pFKey, aChange, bChngRowid)==0 ){
|
| + continue;
|
| + }
|
| +
|
| + if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
|
| + && !pParse->pToplevel && !pParse->isMultiWrite
|
| + ){
|
| + assert( regOld==0 && regNew!=0 );
|
| + /* Inserting a single row into a parent table cannot cause (or fix)
|
| + ** an immediate foreign key violation. So do nothing in this case. */
|
| + continue;
|
| + }
|
| +
|
| + if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
|
| + if( !isIgnoreErrors || db->mallocFailed ) return;
|
| + continue;
|
| + }
|
| + assert( aiCol || pFKey->nCol==1 );
|
| +
|
| + /* Create a SrcList structure containing the child table. We need the
|
| + ** child table as a SrcList for sqlite3WhereBegin() */
|
| + pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
|
| + if( pSrc ){
|
| + struct SrcList_item *pItem = pSrc->a;
|
| + pItem->pTab = pFKey->pFrom;
|
| + pItem->zName = pFKey->pFrom->zName;
|
| + pItem->pTab->nRef++;
|
| + pItem->iCursor = pParse->nTab++;
|
| +
|
| + if( regNew!=0 ){
|
| + fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
|
| + }
|
| + if( regOld!=0 ){
|
| + int eAction = pFKey->aAction[aChange!=0];
|
| + fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
|
| + /* If this is a deferred FK constraint, or a CASCADE or SET NULL
|
| + ** action applies, then any foreign key violations caused by
|
| + ** removing the parent key will be rectified by the action trigger.
|
| + ** So do not set the "may-abort" flag in this case.
|
| + **
|
| + ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the
|
| + ** may-abort flag will eventually be set on this statement anyway
|
| + ** (when this function is called as part of processing the UPDATE
|
| + ** within the action trigger).
|
| + **
|
| + ** Note 2: At first glance it may seem like SQLite could simply omit
|
| + ** all OP_FkCounter related scans when either CASCADE or SET NULL
|
| + ** applies. The trouble starts if the CASCADE or SET NULL action
|
| + ** trigger causes other triggers or action rules attached to the
|
| + ** child table to fire. In these cases the fk constraint counters
|
| + ** might be set incorrectly if any OP_FkCounter related scans are
|
| + ** omitted. */
|
| + if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){
|
| + sqlite3MayAbort(pParse);
|
| + }
|
| + }
|
| + pItem->zName = 0;
|
| + sqlite3SrcListDelete(db, pSrc);
|
| + }
|
| + sqlite3DbFree(db, aiCol);
|
| + }
|
| +}
|
| +
|
| +#define COLUMN_MASK(x) (((x)>31) ? 0xffffffff : ((u32)1<<(x)))
|
| +
|
| +/*
|
| +** This function is called before generating code to update or delete a
|
| +** row contained in table pTab.
|
| +*/
|
| +SQLITE_PRIVATE u32 sqlite3FkOldmask(
|
| + Parse *pParse, /* Parse context */
|
| + Table *pTab /* Table being modified */
|
| +){
|
| + u32 mask = 0;
|
| + if( pParse->db->flags&SQLITE_ForeignKeys ){
|
| + FKey *p;
|
| + int i;
|
| + for(p=pTab->pFKey; p; p=p->pNextFrom){
|
| + for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom);
|
| + }
|
| + for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
| + Index *pIdx = 0;
|
| + sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0);
|
| + if( pIdx ){
|
| + for(i=0; i<pIdx->nKeyCol; i++){
|
| + assert( pIdx->aiColumn[i]>=0 );
|
| + mask |= COLUMN_MASK(pIdx->aiColumn[i]);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return mask;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** This function is called before generating code to update or delete a
|
| +** row contained in table pTab. If the operation is a DELETE, then
|
| +** parameter aChange is passed a NULL value. For an UPDATE, aChange points
|
| +** to an array of size N, where N is the number of columns in table pTab.
|
| +** If the i'th column is not modified by the UPDATE, then the corresponding
|
| +** entry in the aChange[] array is set to -1. If the column is modified,
|
| +** the value is 0 or greater. Parameter chngRowid is set to true if the
|
| +** UPDATE statement modifies the rowid fields of the table.
|
| +**
|
| +** If any foreign key processing will be required, this function returns
|
| +** true. If there is no foreign key related processing, this function
|
| +** returns false.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3FkRequired(
|
| + Parse *pParse, /* Parse context */
|
| + Table *pTab, /* Table being modified */
|
| + int *aChange, /* Non-NULL for UPDATE operations */
|
| + int chngRowid /* True for UPDATE that affects rowid */
|
| +){
|
| + if( pParse->db->flags&SQLITE_ForeignKeys ){
|
| + if( !aChange ){
|
| + /* A DELETE operation. Foreign key processing is required if the
|
| + ** table in question is either the child or parent table for any
|
| + ** foreign key constraint. */
|
| + return (sqlite3FkReferences(pTab) || pTab->pFKey);
|
| + }else{
|
| + /* This is an UPDATE. Foreign key processing is only required if the
|
| + ** operation modifies one or more child or parent key columns. */
|
| + FKey *p;
|
| +
|
| + /* Check if any child key columns are being modified. */
|
| + for(p=pTab->pFKey; p; p=p->pNextFrom){
|
| + if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
|
| + }
|
| +
|
| + /* Check if any parent key columns are being modified. */
|
| + for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
| + if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
|
| + }
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** This function is called when an UPDATE or DELETE operation is being
|
| +** compiled on table pTab, which is the parent table of foreign-key pFKey.
|
| +** If the current operation is an UPDATE, then the pChanges parameter is
|
| +** passed a pointer to the list of columns being modified. If it is a
|
| +** DELETE, pChanges is passed a NULL pointer.
|
| +**
|
| +** It returns a pointer to a Trigger structure containing a trigger
|
| +** equivalent to the ON UPDATE or ON DELETE action specified by pFKey.
|
| +** If the action is "NO ACTION" or "RESTRICT", then a NULL pointer is
|
| +** returned (these actions require no special handling by the triggers
|
| +** sub-system, code for them is created by fkScanChildren()).
|
| +**
|
| +** For example, if pFKey is the foreign key and pTab is table "p" in
|
| +** the following schema:
|
| +**
|
| +** CREATE TABLE p(pk PRIMARY KEY);
|
| +** CREATE TABLE c(ck REFERENCES p ON DELETE CASCADE);
|
| +**
|
| +** then the returned trigger structure is equivalent to:
|
| +**
|
| +** CREATE TRIGGER ... DELETE ON p BEGIN
|
| +** DELETE FROM c WHERE ck = old.pk;
|
| +** END;
|
| +**
|
| +** The returned pointer is cached as part of the foreign key object. It
|
| +** is eventually freed along with the rest of the foreign key object by
|
| +** sqlite3FkDelete().
|
| +*/
|
| +static Trigger *fkActionTrigger(
|
| + Parse *pParse, /* Parse context */
|
| + Table *pTab, /* Table being updated or deleted from */
|
| + FKey *pFKey, /* Foreign key to get action for */
|
| + ExprList *pChanges /* Change-list for UPDATE, NULL for DELETE */
|
| +){
|
| + sqlite3 *db = pParse->db; /* Database handle */
|
| + int action; /* One of OE_None, OE_Cascade etc. */
|
| + Trigger *pTrigger; /* Trigger definition to return */
|
| + int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
|
| +
|
| + action = pFKey->aAction[iAction];
|
| + pTrigger = pFKey->apTrigger[iAction];
|
| +
|
| + if( action!=OE_None && !pTrigger ){
|
| + u8 enableLookaside; /* Copy of db->lookaside.bEnabled */
|
| + char const *zFrom; /* Name of child table */
|
| + int nFrom; /* Length in bytes of zFrom */
|
| + Index *pIdx = 0; /* Parent key index for this FK */
|
| + int *aiCol = 0; /* child table cols -> parent key cols */
|
| + TriggerStep *pStep = 0; /* First (only) step of trigger program */
|
| + Expr *pWhere = 0; /* WHERE clause of trigger step */
|
| + ExprList *pList = 0; /* Changes list if ON UPDATE CASCADE */
|
| + Select *pSelect = 0; /* If RESTRICT, "SELECT RAISE(...)" */
|
| + int i; /* Iterator variable */
|
| + Expr *pWhen = 0; /* WHEN clause for the trigger */
|
| +
|
| + if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0;
|
| + assert( aiCol || pFKey->nCol==1 );
|
| +
|
| + for(i=0; i<pFKey->nCol; i++){
|
| + Token tOld = { "old", 3 }; /* Literal "old" token */
|
| + Token tNew = { "new", 3 }; /* Literal "new" token */
|
| + Token tFromCol; /* Name of column in child table */
|
| + Token tToCol; /* Name of column in parent table */
|
| + int iFromCol; /* Idx of column in child table */
|
| + Expr *pEq; /* tFromCol = OLD.tToCol */
|
| +
|
| + iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
|
| + assert( iFromCol>=0 );
|
| + assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
|
| + assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
|
| + tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
|
| + tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
|
| +
|
| + tToCol.n = sqlite3Strlen30(tToCol.z);
|
| + tFromCol.n = sqlite3Strlen30(tFromCol.z);
|
| +
|
| + /* Create the expression "OLD.zToCol = zFromCol". It is important
|
| + ** that the "OLD.zToCol" term is on the LHS of the = operator, so
|
| + ** that the affinity and collation sequence associated with the
|
| + ** parent table are used for the comparison. */
|
| + pEq = sqlite3PExpr(pParse, TK_EQ,
|
| + sqlite3PExpr(pParse, TK_DOT,
|
| + sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
|
| + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
|
| + , 0),
|
| + sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0)
|
| + , 0);
|
| + pWhere = sqlite3ExprAnd(db, pWhere, pEq);
|
| +
|
| + /* For ON UPDATE, construct the next term of the WHEN clause.
|
| + ** The final WHEN clause will be like this:
|
| + **
|
| + ** WHEN NOT(old.col1 IS new.col1 AND ... AND old.colN IS new.colN)
|
| + */
|
| + if( pChanges ){
|
| + pEq = sqlite3PExpr(pParse, TK_IS,
|
| + sqlite3PExpr(pParse, TK_DOT,
|
| + sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
|
| + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
|
| + 0),
|
| + sqlite3PExpr(pParse, TK_DOT,
|
| + sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
|
| + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
|
| + 0),
|
| + 0);
|
| + pWhen = sqlite3ExprAnd(db, pWhen, pEq);
|
| + }
|
| +
|
| + if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){
|
| + Expr *pNew;
|
| + if( action==OE_Cascade ){
|
| + pNew = sqlite3PExpr(pParse, TK_DOT,
|
| + sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
|
| + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
|
| + , 0);
|
| + }else if( action==OE_SetDflt ){
|
| + Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
|
| + if( pDflt ){
|
| + pNew = sqlite3ExprDup(db, pDflt, 0);
|
| + }else{
|
| + pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
|
| + }
|
| + }else{
|
| + pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
|
| + }
|
| + pList = sqlite3ExprListAppend(pParse, pList, pNew);
|
| + sqlite3ExprListSetName(pParse, pList, &tFromCol, 0);
|
| + }
|
| + }
|
| + sqlite3DbFree(db, aiCol);
|
| +
|
| + zFrom = pFKey->pFrom->zName;
|
| + nFrom = sqlite3Strlen30(zFrom);
|
| +
|
| + if( action==OE_Restrict ){
|
| + Token tFrom;
|
| + Expr *pRaise;
|
| +
|
| + tFrom.z = zFrom;
|
| + tFrom.n = nFrom;
|
| + pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
|
| + if( pRaise ){
|
| + pRaise->affinity = OE_Abort;
|
| + }
|
| + pSelect = sqlite3SelectNew(pParse,
|
| + sqlite3ExprListAppend(pParse, 0, pRaise),
|
| + sqlite3SrcListAppend(db, 0, &tFrom, 0),
|
| + pWhere,
|
| + 0, 0, 0, 0, 0, 0
|
| + );
|
| + pWhere = 0;
|
| + }
|
| +
|
| + /* Disable lookaside memory allocation */
|
| + enableLookaside = db->lookaside.bEnabled;
|
| + db->lookaside.bEnabled = 0;
|
| +
|
| + pTrigger = (Trigger *)sqlite3DbMallocZero(db,
|
| + sizeof(Trigger) + /* struct Trigger */
|
| + sizeof(TriggerStep) + /* Single step in trigger program */
|
| + nFrom + 1 /* Space for pStep->zTarget */
|
| + );
|
| + if( pTrigger ){
|
| + pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
|
| + pStep->zTarget = (char *)&pStep[1];
|
| + memcpy((char *)pStep->zTarget, zFrom, nFrom);
|
| +
|
| + pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
| + pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
|
| + pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
| + if( pWhen ){
|
| + pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0);
|
| + pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
|
| + }
|
| + }
|
| +
|
| + /* Re-enable the lookaside buffer, if it was disabled earlier. */
|
| + db->lookaside.bEnabled = enableLookaside;
|
| +
|
| + sqlite3ExprDelete(db, pWhere);
|
| + sqlite3ExprDelete(db, pWhen);
|
| + sqlite3ExprListDelete(db, pList);
|
| + sqlite3SelectDelete(db, pSelect);
|
| + if( db->mallocFailed==1 ){
|
| + fkTriggerDelete(db, pTrigger);
|
| + return 0;
|
| + }
|
| + assert( pStep!=0 );
|
| +
|
| + switch( action ){
|
| + case OE_Restrict:
|
| + pStep->op = TK_SELECT;
|
| + break;
|
| + case OE_Cascade:
|
| + if( !pChanges ){
|
| + pStep->op = TK_DELETE;
|
| + break;
|
| + }
|
| + default:
|
| + pStep->op = TK_UPDATE;
|
| + }
|
| + pStep->pTrig = pTrigger;
|
| + pTrigger->pSchema = pTab->pSchema;
|
| + pTrigger->pTabSchema = pTab->pSchema;
|
| + pFKey->apTrigger[iAction] = pTrigger;
|
| + pTrigger->op = (pChanges ? TK_UPDATE : TK_DELETE);
|
| + }
|
| +
|
| + return pTrigger;
|
| +}
|
| +
|
| +/*
|
| +** This function is called when deleting or updating a row to implement
|
| +** any required CASCADE, SET NULL or SET DEFAULT actions.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3FkActions(
|
| + Parse *pParse, /* Parse context */
|
| + Table *pTab, /* Table being updated or deleted from */
|
| + ExprList *pChanges, /* Change-list for UPDATE, NULL for DELETE */
|
| + int regOld, /* Address of array containing old row */
|
| + int *aChange, /* Array indicating UPDATEd columns (or 0) */
|
| + int bChngRowid /* True if rowid is UPDATEd */
|
| +){
|
| + /* If foreign-key support is enabled, iterate through all FKs that
|
| + ** refer to table pTab. If there is an action associated with the FK
|
| + ** for this operation (either update or delete), invoke the associated
|
| + ** trigger sub-program. */
|
| + if( pParse->db->flags&SQLITE_ForeignKeys ){
|
| + FKey *pFKey; /* Iterator variable */
|
| + for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
|
| + if( aChange==0 || fkParentIsModified(pTab, pFKey, aChange, bChngRowid) ){
|
| + Trigger *pAct = fkActionTrigger(pParse, pTab, pFKey, pChanges);
|
| + if( pAct ){
|
| + sqlite3CodeRowTriggerDirect(pParse, pAct, pTab, regOld, OE_Abort, 0);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +#endif /* ifndef SQLITE_OMIT_TRIGGER */
|
| +
|
| +/*
|
| +** Free all memory associated with foreign key definitions attached to
|
| +** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash
|
| +** hash table.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
|
| + FKey *pFKey; /* Iterator variable */
|
| + FKey *pNext; /* Copy of pFKey->pNextFrom */
|
| +
|
| + assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
|
| + for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
|
| +
|
| + /* Remove the FK from the fkeyHash hash table. */
|
| + if( !db || db->pnBytesFreed==0 ){
|
| + if( pFKey->pPrevTo ){
|
| + pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
|
| + }else{
|
| + void *p = (void *)pFKey->pNextTo;
|
| + const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
|
| + sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p);
|
| + }
|
| + if( pFKey->pNextTo ){
|
| + pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
|
| + }
|
| + }
|
| +
|
| + /* EV: R-30323-21917 Each foreign key constraint in SQLite is
|
| + ** classified as either immediate or deferred.
|
| + */
|
| + assert( pFKey->isDeferred==0 || pFKey->isDeferred==1 );
|
| +
|
| + /* Delete any triggers created to implement actions for this FK. */
|
| +#ifndef SQLITE_OMIT_TRIGGER
|
| + fkTriggerDelete(db, pFKey->apTrigger[0]);
|
| + fkTriggerDelete(db, pFKey->apTrigger[1]);
|
| +#endif
|
| +
|
| + pNext = pFKey->pNextFrom;
|
| + sqlite3DbFree(db, pFKey);
|
| + }
|
| +}
|
| +#endif /* ifndef SQLITE_OMIT_FOREIGN_KEY */
|
| +
|
| +/************** End of fkey.c ************************************************/
|
| +/************** Begin file insert.c ******************************************/
|
| +/*
|
| +** 2001 September 15
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains C code routines that are called by the parser
|
| +** to handle INSERT statements in SQLite.
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +/*
|
| +** Generate code that will
|
| +**
|
| +** (1) acquire a lock for table pTab then
|
| +** (2) open pTab as cursor iCur.
|
| +**
|
| +** If pTab is a WITHOUT ROWID table, then it is the PRIMARY KEY index
|
| +** for that table that is actually opened.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3OpenTable(
|
| + Parse *pParse, /* 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;
|
| + assert( !IsVirtual(pTab) );
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
|
| + sqlite3TableLock(pParse, iDb, pTab->tnum,
|
| + (opcode==OP_OpenWrite)?1:0, pTab->zName);
|
| + if( HasRowid(pTab) ){
|
| + sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol);
|
| + VdbeComment((v, "%s", pTab->zName));
|
| + }else{
|
| + Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
| + assert( pPk!=0 );
|
| + assert( pPk->tnum==pTab->tnum );
|
| + sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb);
|
| + sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
| + VdbeComment((v, "%s", pTab->zName));
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Return a pointer to the column affinity string associated with index
|
| +** pIdx. A column affinity string has one character for each column in
|
| +** the table, according to the affinity of the column:
|
| +**
|
| +** Character Column affinity
|
| +** ------------------------------
|
| +** 'A' BLOB
|
| +** 'B' TEXT
|
| +** 'C' NUMERIC
|
| +** 'D' INTEGER
|
| +** 'F' REAL
|
| +**
|
| +** An extra 'D' is appended to the end of the string to cover the
|
| +** rowid that appears as the last column in every index.
|
| +**
|
| +** Memory for the buffer containing the column index affinity string
|
| +** is managed along with the rest of the Index structure. It will be
|
| +** released when sqlite3DeleteIndex() is called.
|
| +*/
|
| +SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
|
| + if( !pIdx->zColAff ){
|
| + /* The first time a column affinity string for a particular index is
|
| + ** required, it is allocated and populated here. It is then stored as
|
| + ** a member of the Index structure for subsequent use.
|
| + **
|
| + ** The column affinity string will eventually be deleted by
|
| + ** sqliteDeleteIndex() when the Index structure itself is cleaned
|
| + ** up.
|
| + */
|
| + int n;
|
| + Table *pTab = pIdx->pTable;
|
| + pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
|
| + if( !pIdx->zColAff ){
|
| + db->mallocFailed = 1;
|
| + return 0;
|
| + }
|
| + for(n=0; n<pIdx->nColumn; n++){
|
| + i16 x = pIdx->aiColumn[n];
|
| + if( x>=0 ){
|
| + pIdx->zColAff[n] = pTab->aCol[x].affinity;
|
| + }else if( x==XN_ROWID ){
|
| + pIdx->zColAff[n] = SQLITE_AFF_INTEGER;
|
| + }else{
|
| + char aff;
|
| + assert( x==XN_EXPR );
|
| + assert( pIdx->aColExpr!=0 );
|
| + aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
|
| + if( aff==0 ) aff = SQLITE_AFF_BLOB;
|
| + pIdx->zColAff[n] = aff;
|
| + }
|
| + }
|
| + pIdx->zColAff[n] = 0;
|
| + }
|
| +
|
| + return pIdx->zColAff;
|
| +}
|
| +
|
| +/*
|
| +** Compute the affinity string for table pTab, if it has not already been
|
| +** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities.
|
| +**
|
| +** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and
|
| +** if iReg>0 then code an OP_Affinity opcode that will set the affinities
|
| +** for register iReg and following. Or if affinities exists and iReg==0,
|
| +** then just set the P4 operand of the previous opcode (which should be
|
| +** an OP_MakeRecord) to the affinity string.
|
| +**
|
| +** A column affinity string has one character per column:
|
| +**
|
| +** Character Column affinity
|
| +** ------------------------------
|
| +** 'A' BLOB
|
| +** 'B' TEXT
|
| +** 'C' NUMERIC
|
| +** 'D' INTEGER
|
| +** 'E' REAL
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
| + int i;
|
| + char *zColAff = pTab->zColAff;
|
| + if( zColAff==0 ){
|
| + sqlite3 *db = sqlite3VdbeDb(v);
|
| + zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
|
| + if( !zColAff ){
|
| + db->mallocFailed = 1;
|
| + return;
|
| + }
|
| +
|
| + for(i=0; i<pTab->nCol; i++){
|
| + zColAff[i] = pTab->aCol[i].affinity;
|
| + }
|
| + do{
|
| + zColAff[i--] = 0;
|
| + }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB );
|
| + pTab->zColAff = zColAff;
|
| + }
|
| + i = sqlite3Strlen30(zColAff);
|
| + if( i ){
|
| + if( iReg ){
|
| + sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
|
| + }else{
|
| + sqlite3VdbeChangeP4(v, -1, zColAff, i);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Return non-zero if the table pTab in database iDb or any of its indices
|
| +** have been opened at any point in the VDBE program. This is used to see if
|
| +** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
| +** run without using a temporary table for the results of the SELECT.
|
| +*/
|
| +static int readsTable(Parse *p, int iDb, Table *pTab){
|
| + Vdbe *v = sqlite3GetVdbe(p);
|
| + int i;
|
| + int iEnd = sqlite3VdbeCurrentAddr(v);
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0;
|
| +#endif
|
| +
|
| + for(i=1; i<iEnd; i++){
|
| + VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
|
| + assert( pOp!=0 );
|
| + if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
|
| + Index *pIndex;
|
| + int tnum = pOp->p2;
|
| + if( tnum==pTab->tnum ){
|
| + return 1;
|
| + }
|
| + for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
|
| + if( tnum==pIndex->tnum ){
|
| + return 1;
|
| + }
|
| + }
|
| + }
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pVTab ){
|
| + assert( pOp->p4.pVtab!=0 );
|
| + assert( pOp->p4type==P4_VTAB );
|
| + return 1;
|
| + }
|
| +#endif
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_AUTOINCREMENT
|
| +/*
|
| +** Locate or create an AutoincInfo structure associated with table pTab
|
| +** which is in database iDb. Return the register number for the register
|
| +** that holds the maximum rowid.
|
| +**
|
| +** There is at most one AutoincInfo structure per table even if the
|
| +** same table is autoincremented multiple times due to inserts within
|
| +** triggers. A new AutoincInfo structure is created if this is the
|
| +** first use of table pTab. On 2nd and subsequent uses, the original
|
| +** AutoincInfo structure is used.
|
| +**
|
| +** Three memory locations are allocated:
|
| +**
|
| +** (1) Register to hold the name of the pTab table.
|
| +** (2) Register to hold the maximum ROWID of pTab.
|
| +** (3) Register to hold the rowid in sqlite_sequence of pTab
|
| +**
|
| +** The 2nd register is the one that is returned. That is all the
|
| +** insert routine needs to know about.
|
| +*/
|
| +static int autoIncBegin(
|
| + Parse *pParse, /* Parsing context */
|
| + int iDb, /* Index of the database holding pTab */
|
| + Table *pTab /* The table we are writing to */
|
| +){
|
| + int memId = 0; /* Register holding maximum rowid */
|
| + if( pTab->tabFlags & TF_Autoincrement ){
|
| + Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + AutoincInfo *pInfo;
|
| +
|
| + pInfo = pToplevel->pAinc;
|
| + while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
|
| + if( pInfo==0 ){
|
| + pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
|
| + if( pInfo==0 ) return 0;
|
| + pInfo->pNext = pToplevel->pAinc;
|
| + pToplevel->pAinc = pInfo;
|
| + pInfo->pTab = pTab;
|
| + pInfo->iDb = iDb;
|
| + pToplevel->nMem++; /* Register to hold name of table */
|
| + pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */
|
| + pToplevel->nMem++; /* Rowid in sqlite_sequence */
|
| + }
|
| + memId = pInfo->regCtr;
|
| + }
|
| + return memId;
|
| +}
|
| +
|
| +/*
|
| +** This routine generates code that will initialize all of the
|
| +** register used by the autoincrement tracker.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
|
| + AutoincInfo *p; /* Information about an AUTOINCREMENT */
|
| + sqlite3 *db = pParse->db; /* The database connection */
|
| + Db *pDb; /* Database only autoinc table */
|
| + int memId; /* Register holding max rowid */
|
| + int addr; /* A VDBE address */
|
| + Vdbe *v = pParse->pVdbe; /* VDBE under construction */
|
| +
|
| + /* This routine is never called during trigger-generation. It is
|
| + ** only called from the top-level */
|
| + assert( pParse->pTriggerTab==0 );
|
| + assert( sqlite3IsToplevel(pParse) );
|
| +
|
| + assert( v ); /* We failed long ago if this is not so */
|
| + for(p = pParse->pAinc; p; p = p->pNext){
|
| + pDb = &db->aDb[p->iDb];
|
| + memId = p->regCtr;
|
| + assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
| + sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
|
| + sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
|
| + addr = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
|
| + sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
|
| + sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
|
| + sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
| + sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
|
| + sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
|
| + sqlite3VdbeGoto(v, addr+9);
|
| + sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
|
| + sqlite3VdbeAddOp0(v, OP_Close);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Update the maximum rowid for an autoincrement calculation.
|
| +**
|
| +** This routine should be called when the top of the stack holds a
|
| +** new rowid that is about to be inserted. If that new rowid is
|
| +** larger than the maximum rowid in the memId memory cell, then the
|
| +** memory cell is updated. The stack is unchanged.
|
| +*/
|
| +static void autoIncStep(Parse *pParse, int memId, int regRowid){
|
| + if( memId>0 ){
|
| + sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, regRowid);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This routine generates the code needed to write autoincrement
|
| +** maximum rowid values back into the sqlite_sequence register.
|
| +** Every statement that might do an INSERT into an autoincrement
|
| +** table (either directly or through triggers) needs to call this
|
| +** routine just before the "exit" code.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
|
| + AutoincInfo *p;
|
| + Vdbe *v = pParse->pVdbe;
|
| + sqlite3 *db = pParse->db;
|
| +
|
| + assert( v );
|
| + for(p = pParse->pAinc; p; p = p->pNext){
|
| + Db *pDb = &db->aDb[p->iDb];
|
| + int addr1;
|
| + int iRec;
|
| + int memId = p->regCtr;
|
| +
|
| + iRec = sqlite3GetTempReg(pParse);
|
| + assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
| + sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| + sqlite3VdbeAddOp0(v, OP_Close);
|
| + sqlite3ReleaseTempReg(pParse, iRec);
|
| + }
|
| +}
|
| +#else
|
| +/*
|
| +** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
|
| +** above are all no-ops
|
| +*/
|
| +# define autoIncBegin(A,B,C) (0)
|
| +# define autoIncStep(A,B,C)
|
| +#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
| +
|
| +
|
| +/* Forward declaration */
|
| +static int xferOptimization(
|
| + Parse *pParse, /* Parser context */
|
| + Table *pDest, /* The table we are inserting into */
|
| + Select *pSelect, /* A SELECT statement to use as the data source */
|
| + int onError, /* How to handle constraint errors */
|
| + int iDbDest /* The database of pDest */
|
| +);
|
| +
|
| +/*
|
| +** This routine is called to handle SQL of the following forms:
|
| +**
|
| +** insert into TABLE (IDLIST) values(EXPRLIST),(EXPRLIST),...
|
| +** insert into TABLE (IDLIST) select
|
| +** insert into TABLE (IDLIST) default values
|
| +**
|
| +** The IDLIST following the table name is always optional. If omitted,
|
| +** then a list of all (non-hidden) columns for the table is substituted.
|
| +** The IDLIST appears in the pColumn parameter. pColumn is NULL if IDLIST
|
| +** is omitted.
|
| +**
|
| +** For the pSelect parameter holds the values to be inserted for the
|
| +** first two forms shown above. A VALUES clause is really just short-hand
|
| +** for a SELECT statement that omits the FROM clause and everything else
|
| +** that follows. If the pSelect parameter is NULL, that means that the
|
| +** DEFAULT VALUES form of the INSERT statement is intended.
|
| +**
|
| +** The code generated follows one of four templates. For a simple
|
| +** insert with data coming from a single-row 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
|
| +** put VALUES clause expressions into registers
|
| +** 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:
|
| +**
|
| +** 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
|
| +** end-coroutine X
|
| +** B: open write cursor to <table> and its indices
|
| +** C: yield X, at 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 an intermediate table to store the results of
|
| +** the select. The template is like this:
|
| +**
|
| +** X <- A
|
| +** goto B
|
| +** A: setup for the SELECT
|
| +** loop over the tables in the SELECT
|
| +** load value into register R..R+n
|
| +** yield X
|
| +** end loop
|
| +** cleanup after the SELECT
|
| +** end co-routine R
|
| +** B: open temp table
|
| +** L: yield X, at 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 */
|
| + Select *pSelect, /* A SELECT statement to use as the data source */
|
| + IdList *pColumn, /* Column names corresponding to IDLIST. */
|
| + int onError /* How to handle constraint errors */
|
| +){
|
| + sqlite3 *db; /* The main database structure */
|
| + Table *pTab; /* The table to insert into. aka TABLE */
|
| + char *zTab; /* Name of the table into which we are inserting */
|
| + 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 iDataCur = 0; /* VDBE cursor that is the main data repository */
|
| + int iIdxCur = 0; /* First index cursor */
|
| + int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
| + int endOfLoop; /* Label for the end of the insertion loop */
|
| + 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 */
|
| + SelectDest dest; /* Destination for SELECT on rhs of INSERT */
|
| + int iDb; /* Index of database holding TABLE */
|
| + Db *pDb; /* The database containing table being inserted into */
|
| + u8 useTempTable = 0; /* Store SELECT results in intermediate table */
|
| + u8 appendFlag = 0; /* True if the insert is likely to be an append */
|
| + u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
|
| + u8 bIdListInOrder; /* True if IDLIST is in table order */
|
| + ExprList *pList = 0; /* List of VALUES() to be inserted */
|
| +
|
| + /* Register allocations */
|
| + int regFromSelect = 0;/* Base register for data coming from SELECT */
|
| + int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */
|
| + int regRowCount = 0; /* Memory cell used for the row counter */
|
| + int regIns; /* Block of regs holding rowid+data being inserted */
|
| + int regRowid; /* registers holding insert rowid */
|
| + int regData; /* register holding first column to insert */
|
| + int *aRegIdx = 0; /* One register allocated to each index */
|
| +
|
| +#ifndef SQLITE_OMIT_TRIGGER
|
| + int isView; /* True if attempting to insert into a view */
|
| + Trigger *pTrigger; /* List of triggers on pTab, if required */
|
| + int tmask; /* Mask of trigger times */
|
| +#endif
|
| +
|
| + db = pParse->db;
|
| + memset(&dest, 0, sizeof(dest));
|
| + if( pParse->nErr || db->mallocFailed ){
|
| + goto insert_cleanup;
|
| + }
|
| +
|
| + /* If the Select object is really just a simple VALUES() list with a
|
| + ** single row (the common case) then keep that one row of values
|
| + ** and discard the other (unused) parts of the pSelect object
|
| + */
|
| + if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){
|
| + pList = pSelect->pEList;
|
| + pSelect->pEList = 0;
|
| + sqlite3SelectDelete(db, pSelect);
|
| + pSelect = 0;
|
| + }
|
| +
|
| + /* Locate the table into which we will be inserting new information.
|
| + */
|
| + assert( pTabList->nSrc==1 );
|
| + zTab = pTabList->a[0].zName;
|
| + if( NEVER(zTab==0) ) goto insert_cleanup;
|
| + pTab = sqlite3SrcListLookup(pParse, pTabList);
|
| + if( pTab==0 ){
|
| + goto insert_cleanup;
|
| + }
|
| + iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| + assert( iDb<db->nDb );
|
| + pDb = &db->aDb[iDb];
|
| + zDb = pDb->zName;
|
| + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
|
| + goto insert_cleanup;
|
| + }
|
| + withoutRowid = !HasRowid(pTab);
|
| +
|
| + /* Figure out if we have any triggers and if the table being
|
| + ** inserted into is a view
|
| + */
|
| +#ifndef SQLITE_OMIT_TRIGGER
|
| + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask);
|
| + isView = pTab->pSelect!=0;
|
| +#else
|
| +# define pTrigger 0
|
| +# define tmask 0
|
| +# define isView 0
|
| +#endif
|
| +#ifdef SQLITE_OMIT_VIEW
|
| +# undef isView
|
| +# define isView 0
|
| +#endif
|
| + assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
|
| +
|
| + /* If pTab is really a view, make sure it has been initialized.
|
| + ** ViewGetColumnNames() is a no-op if pTab is not a view.
|
| + */
|
| + if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
| + goto insert_cleanup;
|
| + }
|
| +
|
| + /* Cannot insert into a read-only table.
|
| + */
|
| + if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
|
| + goto insert_cleanup;
|
| + }
|
| +
|
| + /* Allocate a VDBE
|
| + */
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v==0 ) goto insert_cleanup;
|
| + if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
| + sqlite3BeginWriteOperation(pParse, pSelect || pTrigger, iDb);
|
| +
|
| +#ifndef SQLITE_OMIT_XFER_OPT
|
| + /* If the statement is of the form
|
| + **
|
| + ** INSERT INTO <table1> SELECT * FROM <table2>;
|
| + **
|
| + ** Then special optimizations can be applied that make the transfer
|
| + ** very fast and which reduce fragmentation of indices.
|
| + **
|
| + ** This is the 2nd template.
|
| + */
|
| + if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
|
| + assert( !pTrigger );
|
| + assert( pList==0 );
|
| + goto insert_end;
|
| + }
|
| +#endif /* SQLITE_OMIT_XFER_OPT */
|
| +
|
| + /* If this is an AUTOINCREMENT table, look up the sequence number in the
|
| + ** sqlite_sequence table and store it in memory cell regAutoinc.
|
| + */
|
| + regAutoinc = autoIncBegin(pParse, iDb, pTab);
|
| +
|
| + /* Allocate registers for holding the rowid of the new row,
|
| + ** the content of the new row, and the assembled row record.
|
| + */
|
| + regRowid = regIns = pParse->nMem+1;
|
| + pParse->nMem += pTab->nCol + 1;
|
| + if( IsVirtual(pTab) ){
|
| + regRowid++;
|
| + pParse->nMem++;
|
| + }
|
| + regData = regRowid+1;
|
| +
|
| + /* If the INSERT statement included an IDLIST term, then make sure
|
| + ** all elements of the IDLIST really are columns of the table and
|
| + ** remember the column indices.
|
| + **
|
| + ** If the table has an INTEGER PRIMARY KEY column and that column
|
| + ** is named in the IDLIST, then record in the ipkColumn variable
|
| + ** the index into IDLIST of the primary key column. ipkColumn is
|
| + ** the index of the primary key as it appears in IDLIST, not as
|
| + ** is appears in the original table. (The index of the INTEGER
|
| + ** PRIMARY KEY in the original table is pTab->iPKey.)
|
| + */
|
| + bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0;
|
| + if( pColumn ){
|
| + for(i=0; i<pColumn->nId; i++){
|
| + pColumn->a[i].idx = -1;
|
| + }
|
| + for(i=0; i<pColumn->nId; i++){
|
| + for(j=0; j<pTab->nCol; j++){
|
| + if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
|
| + pColumn->a[i].idx = j;
|
| + if( i!=j ) bIdListInOrder = 0;
|
| + if( j==pTab->iPKey ){
|
| + ipkColumn = i; assert( !withoutRowid );
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + if( j>=pTab->nCol ){
|
| + if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){
|
| + ipkColumn = i;
|
| + bIdListInOrder = 0;
|
| + }else{
|
| + sqlite3ErrorMsg(pParse, "table %S has no column named %s",
|
| + pTabList, 0, pColumn->a[i].zName);
|
| + pParse->checkSchema = 1;
|
| + goto insert_cleanup;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Figure out how many columns of data are supplied. If the data
|
| + ** is coming from a SELECT statement, then generate a co-routine that
|
| + ** produces a single row of the SELECT on each invocation. The
|
| + ** co-routine is the common header to the 3rd and 4th templates.
|
| + */
|
| + if( pSelect ){
|
| + /* Data is coming from a SELECT or from a multi-row VALUES clause.
|
| + ** Generate a co-routine to run the SELECT. */
|
| + int regYield; /* Register holding co-routine entry-point */
|
| + int addrTop; /* Top of the co-routine */
|
| + int rc; /* Result code */
|
| +
|
| + regYield = ++pParse->nMem;
|
| + addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
| + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
| + sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
|
| + dest.iSdst = bIdListInOrder ? regData : 0;
|
| + dest.nSdst = pTab->nCol;
|
| + rc = sqlite3Select(pParse, pSelect, &dest);
|
| + regFromSelect = dest.iSdst;
|
| + if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
|
| + sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
| + sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
| + assert( pSelect->pEList );
|
| + nColumn = pSelect->pEList->nExpr;
|
| +
|
| + /* Set useTempTable to TRUE if the result of the SELECT statement
|
| + ** should be written into a temporary table (template 4). Set to
|
| + ** FALSE if each output row of the SELECT can be written directly into
|
| + ** the destination table (template 3).
|
| + **
|
| + ** A temp table must be used if the table being updated is also one
|
| + ** of the tables being read by the SELECT statement. Also use a
|
| + ** temp table in the case of row triggers.
|
| + */
|
| + if( pTrigger || readsTable(pParse, iDb, pTab) ){
|
| + useTempTable = 1;
|
| + }
|
| +
|
| + if( useTempTable ){
|
| + /* Invoke the coroutine to extract information from the SELECT
|
| + ** and add it to a transient table srcTab. The code generated
|
| + ** here is from the 4th template:
|
| + **
|
| + ** B: open temp table
|
| + ** L: yield X, goto M at EOF
|
| + ** insert row from R..R+n into temp table
|
| + ** goto L
|
| + ** M: ...
|
| + */
|
| + int regRec; /* Register to hold packed record */
|
| + int regTempRowid; /* Register to hold temp table ROWID */
|
| + int addrL; /* Label "L" */
|
| +
|
| + srcTab = pParse->nTab++;
|
| + regRec = sqlite3GetTempReg(pParse);
|
| + regTempRowid = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
| + addrL = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
|
| + sqlite3VdbeGoto(v, addrL);
|
| + sqlite3VdbeJumpHere(v, addrL);
|
| + sqlite3ReleaseTempReg(pParse, regRec);
|
| + sqlite3ReleaseTempReg(pParse, regTempRowid);
|
| + }
|
| + }else{
|
| + /* This is the case if the data for the INSERT is coming from a
|
| + ** single-row VALUES clause
|
| + */
|
| + NameContext sNC;
|
| + memset(&sNC, 0, sizeof(sNC));
|
| + sNC.pParse = pParse;
|
| + srcTab = -1;
|
| + assert( useTempTable==0 );
|
| + if( pList ){
|
| + nColumn = pList->nExpr;
|
| + if( sqlite3ResolveExprListNames(&sNC, pList) ){
|
| + goto insert_cleanup;
|
| + }
|
| + }else{
|
| + nColumn = 0;
|
| + }
|
| + }
|
| +
|
| + /* If there is no IDLIST term but the table has an integer primary
|
| + ** key, the set the ipkColumn variable to the integer primary key
|
| + ** column index in the original table definition.
|
| + */
|
| + if( pColumn==0 && nColumn>0 ){
|
| + ipkColumn = pTab->iPKey;
|
| + }
|
| +
|
| + /* Make sure the number of columns in the source data matches the number
|
| + ** of columns to be inserted into the table.
|
| + */
|
| + for(i=0; i<pTab->nCol; i++){
|
| + nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
|
| + }
|
| + if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "table %S has %d columns but %d values were supplied",
|
| + pTabList, 0, pTab->nCol-nHidden, nColumn);
|
| + goto insert_cleanup;
|
| + }
|
| + if( pColumn!=0 && nColumn!=pColumn->nId ){
|
| + sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
|
| + goto insert_cleanup;
|
| + }
|
| +
|
| + /* Initialize the count of rows to be inserted
|
| + */
|
| + if( db->flags & SQLITE_CountRows ){
|
| + regRowCount = ++pParse->nMem;
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
|
| + }
|
| +
|
| + /* If this is not a view, open the table and and all indices */
|
| + if( !isView ){
|
| + int nIdx;
|
| + nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
|
| + &iDataCur, &iIdxCur);
|
| + aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
|
| + if( aRegIdx==0 ){
|
| + goto insert_cleanup;
|
| + }
|
| + for(i=0; i<nIdx; i++){
|
| + aRegIdx[i] = ++pParse->nMem;
|
| + }
|
| + }
|
| +
|
| + /* This is the top of the main insertion loop */
|
| + if( useTempTable ){
|
| + /* This block codes the top of loop only. The complete loop is the
|
| + ** following pseudocode (template 4):
|
| + **
|
| + ** rewind temp table, if empty goto D
|
| + ** C: loop over rows of intermediate table
|
| + ** transfer values form intermediate table into <table>
|
| + ** end loop
|
| + ** D: ...
|
| + */
|
| + addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab); VdbeCoverage(v);
|
| + addrCont = sqlite3VdbeCurrentAddr(v);
|
| + }else if( pSelect ){
|
| + /* This block codes the top of loop only. The complete loop is the
|
| + ** following pseudocode (template 3):
|
| + **
|
| + ** C: yield X, at EOF goto D
|
| + ** insert the select result into <table> from R..R+n
|
| + ** goto C
|
| + ** D: ...
|
| + */
|
| + addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
| + VdbeCoverage(v);
|
| + }
|
| +
|
| + /* Run the BEFORE and INSTEAD OF triggers, if there are any
|
| + */
|
| + endOfLoop = sqlite3VdbeMakeLabel(v);
|
| + if( tmask & TRIGGER_BEFORE ){
|
| + int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1);
|
| +
|
| + /* build the NEW.* reference row. Note that if there is an INTEGER
|
| + ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
|
| + ** translated into a unique ID for the row. But on a BEFORE trigger,
|
| + ** we do not know what the unique ID will be (because the insert has
|
| + ** not happened yet) so we substitute a rowid of -1
|
| + */
|
| + if( ipkColumn<0 ){
|
| + sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
|
| + }else{
|
| + int addr1;
|
| + assert( !withoutRowid );
|
| + if( useTempTable ){
|
| + sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols);
|
| + }else{
|
| + assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
| + sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols);
|
| + }
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
|
| + }
|
| +
|
| + /* Cannot have triggers on a virtual table. If it were possible,
|
| + ** this block would have to account for hidden column.
|
| + */
|
| + assert( !IsVirtual(pTab) );
|
| +
|
| + /* Create the new column data
|
| + */
|
| + for(i=j=0; i<pTab->nCol; i++){
|
| + if( pColumn ){
|
| + for(j=0; j<pColumn->nId; j++){
|
| + if( pColumn->a[j].idx==i ) break;
|
| + }
|
| + }
|
| + if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId)
|
| + || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){
|
| + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
|
| + }else if( useTempTable ){
|
| + sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
|
| + }else{
|
| + assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
| + sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
|
| + }
|
| + if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++;
|
| + }
|
| +
|
| + /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
|
| + ** do not attempt any conversions before assembling the record.
|
| + ** If this is a real table, attempt conversions as required by the
|
| + ** table column affinities.
|
| + */
|
| + if( !isView ){
|
| + sqlite3TableAffinity(v, pTab, regCols+1);
|
| + }
|
| +
|
| + /* Fire BEFORE or INSTEAD OF triggers */
|
| + sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
|
| + pTab, regCols-pTab->nCol-1, onError, endOfLoop);
|
| +
|
| + sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1);
|
| + }
|
| +
|
| + /* Compute the content of the next row to insert into a range of
|
| + ** registers beginning at regIns.
|
| + */
|
| + if( !isView ){
|
| + if( IsVirtual(pTab) ){
|
| + /* The row that the VUpdate opcode will delete: none */
|
| + sqlite3VdbeAddOp2(v, OP_Null, 0, regIns);
|
| + }
|
| + if( ipkColumn>=0 ){
|
| + if( useTempTable ){
|
| + sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid);
|
| + }else if( pSelect ){
|
| + sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
|
| + }else{
|
| + VdbeOp *pOp;
|
| + sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
|
| + pOp = sqlite3VdbeGetOp(v, -1);
|
| + if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
|
| + appendFlag = 1;
|
| + pOp->opcode = OP_NewRowid;
|
| + pOp->p1 = iDataCur;
|
| + pOp->p2 = regRowid;
|
| + pOp->p3 = regAutoinc;
|
| + }
|
| + }
|
| + /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
|
| + ** to generate a unique primary key value.
|
| + */
|
| + if( !appendFlag ){
|
| + int addr1;
|
| + if( !IsVirtual(pTab) ){
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + }else{
|
| + addr1 = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v);
|
| + }
|
| + }else if( IsVirtual(pTab) || withoutRowid ){
|
| + sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
|
| + }else{
|
| + sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
|
| + appendFlag = 1;
|
| + }
|
| + autoIncStep(pParse, regAutoinc, regRowid);
|
| +
|
| + /* Compute data for all columns of the new entry, beginning
|
| + ** with the first column.
|
| + */
|
| + nHidden = 0;
|
| + for(i=0; i<pTab->nCol; i++){
|
| + int iRegStore = regRowid+1+i;
|
| + if( i==pTab->iPKey ){
|
| + /* The value of the INTEGER PRIMARY KEY column is always a NULL.
|
| + ** Whenever this column is read, the rowid will be substituted
|
| + ** in its place. Hence, fill this column with a NULL to avoid
|
| + ** taking up data space with information that will never be used.
|
| + ** As there may be shallow copies of this value, make it a soft-NULL */
|
| + sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
|
| + continue;
|
| + }
|
| + if( pColumn==0 ){
|
| + if( IsHiddenColumn(&pTab->aCol[i]) ){
|
| + j = -1;
|
| + nHidden++;
|
| + }else{
|
| + j = i - nHidden;
|
| + }
|
| + }else{
|
| + for(j=0; j<pColumn->nId; j++){
|
| + if( pColumn->a[j].idx==i ) break;
|
| + }
|
| + }
|
| + if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
|
| + sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
|
| + }else if( useTempTable ){
|
| + sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
|
| + }else if( pSelect ){
|
| + if( regFromSelect!=regData ){
|
| + sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
|
| + }
|
| + }else{
|
| + sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
|
| + }
|
| + }
|
| +
|
| + /* Generate code to check constraints and generate index keys and
|
| + ** do the insertion.
|
| + */
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( IsVirtual(pTab) ){
|
| + const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
| + sqlite3VtabMakeWritable(pParse, pTab);
|
| + sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
|
| + sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
|
| + sqlite3MayAbort(pParse);
|
| + }else
|
| +#endif
|
| + {
|
| + int isReplace; /* Set to true if constraints may cause a replace */
|
| + sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
|
| + regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace
|
| + );
|
| + sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
|
| + sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
|
| + regIns, aRegIdx, 0, appendFlag, isReplace==0);
|
| + }
|
| + }
|
| +
|
| + /* Update the count of rows that are inserted
|
| + */
|
| + if( (db->flags & SQLITE_CountRows)!=0 ){
|
| + sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
|
| + }
|
| +
|
| + if( pTrigger ){
|
| + /* Code AFTER triggers */
|
| + sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
|
| + pTab, regData-2-pTab->nCol, onError, endOfLoop);
|
| + }
|
| +
|
| + /* The bottom of the main insertion loop, if the data source
|
| + ** is a SELECT statement.
|
| + */
|
| + sqlite3VdbeResolveLabel(v, endOfLoop);
|
| + if( useTempTable ){
|
| + sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addrInsTop);
|
| + sqlite3VdbeAddOp1(v, OP_Close, srcTab);
|
| + }else if( pSelect ){
|
| + sqlite3VdbeGoto(v, addrCont);
|
| + sqlite3VdbeJumpHere(v, addrInsTop);
|
| + }
|
| +
|
| + if( !IsVirtual(pTab) && !isView ){
|
| + /* Close all tables opened */
|
| + if( iDataCur<iIdxCur ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
|
| + for(idx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
| + sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur);
|
| + }
|
| + }
|
| +
|
| +insert_end:
|
| + /* Update the sqlite_sequence table by storing the content of the
|
| + ** maximum rowid counter values recorded while inserting into
|
| + ** autoincrement tables.
|
| + */
|
| + if( pParse->nested==0 && pParse->pTriggerTab==0 ){
|
| + sqlite3AutoincrementEnd(pParse);
|
| + }
|
| +
|
| + /*
|
| + ** Return the number of rows inserted. If this routine is
|
| + ** generating code because of a call to sqlite3NestedParse(), do not
|
| + ** invoke the callback function.
|
| + */
|
| + if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
|
| + sqlite3VdbeSetNumCols(v, 1);
|
| + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC);
|
| + }
|
| +
|
| +insert_cleanup:
|
| + sqlite3SrcListDelete(db, pTabList);
|
| + sqlite3ExprListDelete(db, pList);
|
| + sqlite3SelectDelete(db, pSelect);
|
| + sqlite3IdListDelete(db, pColumn);
|
| + sqlite3DbFree(db, aRegIdx);
|
| +}
|
| +
|
| +/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
| +** they may interfere with compilation of other functions in this file
|
| +** (or in another file, if this file becomes part of the amalgamation). */
|
| +#ifdef isView
|
| + #undef isView
|
| +#endif
|
| +#ifdef pTrigger
|
| + #undef pTrigger
|
| +#endif
|
| +#ifdef tmask
|
| + #undef tmask
|
| +#endif
|
| +
|
| +/*
|
| +** Generate code to do constraint checks prior to an INSERT or an UPDATE
|
| +** on table pTab.
|
| +**
|
| +** The regNewData parameter is the first register in a range that contains
|
| +** the data to be inserted or the data after the update. There will be
|
| +** pTab->nCol+1 registers in this range. The first register (the one
|
| +** that regNewData points to) will contain the new rowid, or NULL in the
|
| +** case of a WITHOUT ROWID table. The second register in the range will
|
| +** contain the content of the first table column. The third register will
|
| +** contain the content of the second table column. And so forth.
|
| +**
|
| +** The regOldData parameter is similar to regNewData except that it contains
|
| +** the data prior to an UPDATE rather than afterwards. regOldData is zero
|
| +** for an INSERT. This routine can distinguish between UPDATE and INSERT by
|
| +** checking regOldData for zero.
|
| +**
|
| +** For an UPDATE, the pkChng boolean is true if the true primary key (the
|
| +** rowid for a normal table or the PRIMARY KEY for a WITHOUT ROWID table)
|
| +** might be modified by the UPDATE. If pkChng is false, then the key of
|
| +** the iDataCur content table is guaranteed to be unchanged by the UPDATE.
|
| +**
|
| +** For an INSERT, the pkChng boolean indicates whether or not the rowid
|
| +** was explicitly specified as part of the INSERT statement. If pkChng
|
| +** is zero, it means that the either rowid is computed automatically or
|
| +** that the table is a WITHOUT ROWID table and has no rowid. On an INSERT,
|
| +** pkChng will only be true if the INSERT statement provides an integer
|
| +** value for either the rowid column or its INTEGER PRIMARY KEY alias.
|
| +**
|
| +** The code generated by this routine will store new index entries into
|
| +** registers identified by aRegIdx[]. No index entry is created for
|
| +** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is
|
| +** the same as the order of indices on the linked list of indices
|
| +** at pTab->pIndex.
|
| +**
|
| +** The caller must have already opened writeable cursors on the main
|
| +** table and all applicable indices (that is to say, all indices for which
|
| +** aRegIdx[] is not zero). iDataCur is the cursor for the main table when
|
| +** inserting or updating a rowid table, or the cursor for the PRIMARY KEY
|
| +** index when operating on a WITHOUT ROWID table. iIdxCur is the cursor
|
| +** for the first index in the pTab->pIndex list. Cursors for other indices
|
| +** are at iIdxCur+N for the N-th element of the pTab->pIndex list.
|
| +**
|
| +** This routine also generates code to check constraints. NOT NULL,
|
| +** CHECK, and UNIQUE constraints are all checked. If a constraint fails,
|
| +** then the appropriate action is performed. There are five possible
|
| +** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE.
|
| +**
|
| +** Constraint type Action What Happens
|
| +** --------------- ---------- ----------------------------------------
|
| +** any ROLLBACK The current transaction is rolled back and
|
| +** sqlite3_step() returns immediately with a
|
| +** return code of SQLITE_CONSTRAINT.
|
| +**
|
| +** any ABORT Back out changes from the current command
|
| +** only (do not do a complete rollback) then
|
| +** cause sqlite3_step() to return immediately
|
| +** with SQLITE_CONSTRAINT.
|
| +**
|
| +** any FAIL Sqlite3_step() returns immediately with a
|
| +** return code of SQLITE_CONSTRAINT. The
|
| +** transaction is not rolled back and any
|
| +** changes to prior rows are retained.
|
| +**
|
| +** any IGNORE The attempt in insert or update the current
|
| +** row is skipped, without throwing an error.
|
| +** Processing continues with the next row.
|
| +** (There is an immediate jump to ignoreDest.)
|
| +**
|
| +** NOT NULL REPLACE The NULL value is replace by the default
|
| +** value for that column. If the default value
|
| +** is NULL, the action is the same as ABORT.
|
| +**
|
| +** 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.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
| + Parse *pParse, /* The parser context */
|
| + Table *pTab, /* The table being inserted or updated */
|
| + int *aRegIdx, /* Use register aRegIdx[i] for index i. 0 for unused */
|
| + int iDataCur, /* Canonical data cursor (main table or PK index) */
|
| + int iIdxCur, /* First index cursor */
|
| + int regNewData, /* First register in a range holding values to insert */
|
| + int regOldData, /* Previous content. 0 for INSERTs */
|
| + u8 pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
|
| + u8 overrideError, /* Override onError to this if not OE_Default */
|
| + int ignoreDest, /* Jump to this label on an OE_Ignore resolution */
|
| + int *pbMayReplace /* OUT: Set to true if constraint may cause a replace */
|
| +){
|
| + Vdbe *v; /* VDBE under constrution */
|
| + Index *pIdx; /* Pointer to one of the indices */
|
| + Index *pPk = 0; /* The PRIMARY KEY index */
|
| + sqlite3 *db; /* Database connection */
|
| + int i; /* loop counter */
|
| + int ix; /* Index loop counter */
|
| + int nCol; /* Number of columns */
|
| + int onError; /* Conflict resolution strategy */
|
| + int addr1; /* Address of jump instruction */
|
| + int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
| + int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
| + int ipkTop = 0; /* Top of the rowid change constraint check */
|
| + int ipkBottom = 0; /* Bottom of the rowid change constraint check */
|
| + u8 isUpdate; /* True if this is an UPDATE operation */
|
| + u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
| + int regRowid = -1; /* Register holding ROWID value */
|
| +
|
| + isUpdate = regOldData!=0;
|
| + db = pParse->db;
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( v!=0 );
|
| + assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
| + nCol = pTab->nCol;
|
| +
|
| + /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
|
| + ** normal rowid tables. nPkField is the number of key fields in the
|
| + ** pPk index or 1 for a rowid table. In other words, nPkField is the
|
| + ** number of fields in the true primary key of the table. */
|
| + if( HasRowid(pTab) ){
|
| + pPk = 0;
|
| + nPkField = 1;
|
| + }else{
|
| + pPk = sqlite3PrimaryKeyIndex(pTab);
|
| + nPkField = pPk->nKeyCol;
|
| + }
|
| +
|
| + /* Record that this module has started */
|
| + VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
|
| + iDataCur, iIdxCur, regNewData, regOldData, pkChng));
|
| +
|
| + /* Test all NOT NULL constraints.
|
| + */
|
| + for(i=0; i<nCol; i++){
|
| + if( i==pTab->iPKey ){
|
| + continue;
|
| + }
|
| + onError = pTab->aCol[i].notNull;
|
| + if( onError==OE_None ) continue;
|
| + if( overrideError!=OE_Default ){
|
| + onError = overrideError;
|
| + }else if( onError==OE_Default ){
|
| + onError = OE_Abort;
|
| + }
|
| + if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
|
| + onError = OE_Abort;
|
| + }
|
| + assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|
| + || onError==OE_Ignore || onError==OE_Replace );
|
| + switch( onError ){
|
| + case OE_Abort:
|
| + sqlite3MayAbort(pParse);
|
| + /* Fall through */
|
| + case OE_Rollback:
|
| + case OE_Fail: {
|
| + char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
|
| + pTab->aCol[i].zName);
|
| + sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
|
| + regNewData+1+i, zMsg, P4_DYNAMIC);
|
| + sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
|
| + VdbeCoverage(v);
|
| + break;
|
| + }
|
| + case OE_Ignore: {
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest);
|
| + VdbeCoverage(v);
|
| + break;
|
| + }
|
| + default: {
|
| + assert( onError==OE_Replace );
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
|
| + VdbeCoverage(v);
|
| + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Test all CHECK constraints
|
| + */
|
| +#ifndef SQLITE_OMIT_CHECK
|
| + if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
|
| + ExprList *pCheck = pTab->pCheck;
|
| + pParse->ckBase = regNewData+1;
|
| + onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
| + for(i=0; i<pCheck->nExpr; i++){
|
| + int allOk = sqlite3VdbeMakeLabel(v);
|
| + sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
|
| + if( onError==OE_Ignore ){
|
| + sqlite3VdbeGoto(v, ignoreDest);
|
| + }else{
|
| + char *zName = pCheck->a[i].zName;
|
| + if( zName==0 ) zName = pTab->zName;
|
| + if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
|
| + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
|
| + onError, zName, P4_TRANSIENT,
|
| + P5_ConstraintCheck);
|
| + }
|
| + sqlite3VdbeResolveLabel(v, allOk);
|
| + }
|
| + }
|
| +#endif /* !defined(SQLITE_OMIT_CHECK) */
|
| +
|
| + /* If rowid is changing, make sure the new rowid does not previously
|
| + ** exist in the table.
|
| + */
|
| + if( pkChng && pPk==0 ){
|
| + int addrRowidOk = sqlite3VdbeMakeLabel(v);
|
| +
|
| + /* Figure out what action to take in case of a rowid collision */
|
| + onError = pTab->keyConf;
|
| + if( overrideError!=OE_Default ){
|
| + onError = overrideError;
|
| + }else if( onError==OE_Default ){
|
| + onError = OE_Abort;
|
| + }
|
| +
|
| + if( isUpdate ){
|
| + /* pkChng!=0 does not mean that the rowid has change, only that
|
| + ** it might have changed. Skip the conflict logic below if the rowid
|
| + ** is unchanged. */
|
| + sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
|
| + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
| + VdbeCoverage(v);
|
| + }
|
| +
|
| + /* If the response to a rowid conflict is REPLACE but the response
|
| + ** to some other UNIQUE constraint is FAIL or IGNORE, then we need
|
| + ** to defer the running of the rowid conflict checking until after
|
| + ** the UNIQUE constraints have run.
|
| + */
|
| + if( onError==OE_Replace && overrideError!=OE_Replace ){
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + if( pIdx->onError==OE_Ignore || pIdx->onError==OE_Fail ){
|
| + ipkTop = sqlite3VdbeAddOp0(v, OP_Goto);
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Check to see if the new rowid already exists in the table. Skip
|
| + ** the following conflict logic if it does not. */
|
| + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
|
| + VdbeCoverage(v);
|
| +
|
| + /* Generate code that deals with a rowid collision */
|
| + switch( onError ){
|
| + default: {
|
| + onError = OE_Abort;
|
| + /* Fall thru into the next case */
|
| + }
|
| + case OE_Rollback:
|
| + case OE_Abort:
|
| + case OE_Fail: {
|
| + sqlite3RowidConstraint(pParse, onError, pTab);
|
| + break;
|
| + }
|
| + case OE_Replace: {
|
| + /* If there are DELETE triggers on this table and the
|
| + ** recursive-triggers flag is set, call GenerateRowDelete() to
|
| + ** remove the conflicting row from the table. This will fire
|
| + ** the triggers and remove both the table and index b-tree entries.
|
| + **
|
| + ** Otherwise, if there are no triggers or the recursive-triggers
|
| + ** flag is not set, but the table has one or more indexes, call
|
| + ** GenerateRowIndexDelete(). This removes the index b-tree entries
|
| + ** only. The table b-tree entry will be replaced by the new entry
|
| + ** when it is inserted.
|
| + **
|
| + ** If either GenerateRowDelete() or GenerateRowIndexDelete() is called,
|
| + ** also invoke MultiWrite() to indicate that this VDBE may require
|
| + ** statement rollback (if the statement is aborted after the delete
|
| + ** takes place). Earlier versions called sqlite3MultiWrite() regardless,
|
| + ** but being more selective here allows statements like:
|
| + **
|
| + ** REPLACE INTO t(rowid) VALUES($newrowid)
|
| + **
|
| + ** to run without a statement journal if there are no indexes on the
|
| + ** table.
|
| + */
|
| + Trigger *pTrigger = 0;
|
| + if( db->flags&SQLITE_RecTriggers ){
|
| + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
| + }
|
| + if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
|
| + sqlite3MultiWrite(pParse);
|
| + sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
| + regNewData, 1, 0, OE_Replace,
|
| + ONEPASS_SINGLE, -1);
|
| + }else{
|
| + if( pTab->pIndex ){
|
| + sqlite3MultiWrite(pParse);
|
| + sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
|
| + }
|
| + }
|
| + seenReplace = 1;
|
| + break;
|
| + }
|
| + case OE_Ignore: {
|
| + /*assert( seenReplace==0 );*/
|
| + sqlite3VdbeGoto(v, ignoreDest);
|
| + break;
|
| + }
|
| + }
|
| + sqlite3VdbeResolveLabel(v, addrRowidOk);
|
| + if( ipkTop ){
|
| + ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
|
| + sqlite3VdbeJumpHere(v, ipkTop);
|
| + }
|
| + }
|
| +
|
| + /* Test all UNIQUE constraints by creating entries for each UNIQUE
|
| + ** index and making sure that duplicate entries do not already exist.
|
| + ** Compute the revised record entries for indices as we go.
|
| + **
|
| + ** This loop also handles the case of the PRIMARY KEY index for a
|
| + ** WITHOUT ROWID table.
|
| + */
|
| + for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
|
| + int regIdx; /* Range of registers hold conent for pIdx */
|
| + int regR; /* Range of registers holding conflicting PK */
|
| + int iThisCur; /* Cursor for this UNIQUE index */
|
| + int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
|
| +
|
| + if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
| + if( bAffinityDone==0 ){
|
| + sqlite3TableAffinity(v, pTab, regNewData+1);
|
| + bAffinityDone = 1;
|
| + }
|
| + iThisCur = iIdxCur+ix;
|
| + addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
| +
|
| + /* Skip partial indices for which the WHERE clause is not true */
|
| + if( pIdx->pPartIdxWhere ){
|
| + sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
|
| + pParse->ckBase = regNewData+1;
|
| + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
|
| + SQLITE_JUMPIFNULL);
|
| + pParse->ckBase = 0;
|
| + }
|
| +
|
| + /* Create a record for this index entry as it should appear after
|
| + ** the insert or update. Store that record in the aRegIdx[ix] register
|
| + */
|
| + regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
|
| + for(i=0; i<pIdx->nColumn; i++){
|
| + int iField = pIdx->aiColumn[i];
|
| + int x;
|
| + if( iField==XN_EXPR ){
|
| + pParse->ckBase = regNewData+1;
|
| + sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
|
| + pParse->ckBase = 0;
|
| + VdbeComment((v, "%s column %d", pIdx->zName, i));
|
| + }else{
|
| + if( iField==XN_ROWID || iField==pTab->iPKey ){
|
| + if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
|
| + x = regNewData;
|
| + regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
|
| + }else{
|
| + x = iField + regNewData + 1;
|
| + }
|
| + sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i);
|
| + VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
|
| + }
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
|
| + VdbeComment((v, "for %s", pIdx->zName));
|
| + sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
|
| +
|
| + /* In an UPDATE operation, if this index is the PRIMARY KEY index
|
| + ** of a WITHOUT ROWID table and there has been no change the
|
| + ** primary key, then no collision is possible. The collision detection
|
| + ** logic below can all be skipped. */
|
| + if( isUpdate && pPk==pIdx && pkChng==0 ){
|
| + sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
| + continue;
|
| + }
|
| +
|
| + /* Find out what action to take in case there is a uniqueness conflict */
|
| + onError = pIdx->onError;
|
| + if( onError==OE_None ){
|
| + sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
| + sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
| + continue; /* pIdx is not a UNIQUE index */
|
| + }
|
| + if( overrideError!=OE_Default ){
|
| + onError = overrideError;
|
| + }else if( onError==OE_Default ){
|
| + onError = OE_Abort;
|
| + }
|
| +
|
| + /* Check to see if the new index entry will be unique */
|
| + sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
|
| + regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
| +
|
| + /* Generate code to handle collisions */
|
| + regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
| + if( isUpdate || onError==OE_Replace ){
|
| + if( HasRowid(pTab) ){
|
| + sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
| + /* Conflict only if the rowid of the existing index entry
|
| + ** is different from old-rowid */
|
| + if( isUpdate ){
|
| + sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
|
| + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
| + VdbeCoverage(v);
|
| + }
|
| + }else{
|
| + int x;
|
| + /* Extract the PRIMARY KEY from the end of the index entry and
|
| + ** store it in registers regR..regR+nPk-1 */
|
| + if( pIdx!=pPk ){
|
| + for(i=0; i<pPk->nKeyCol; i++){
|
| + assert( pPk->aiColumn[i]>=0 );
|
| + x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
|
| + sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
|
| + VdbeComment((v, "%s.%s", pTab->zName,
|
| + pTab->aCol[pPk->aiColumn[i]].zName));
|
| + }
|
| + }
|
| + if( isUpdate ){
|
| + /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
|
| + ** table, only conflict if the new PRIMARY KEY values are actually
|
| + ** different from the old.
|
| + **
|
| + ** For a UNIQUE index, only conflict if the PRIMARY KEY values
|
| + ** of the matched index row are different from the original PRIMARY
|
| + ** KEY values of this row before the update. */
|
| + int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
|
| + int op = OP_Ne;
|
| + int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR);
|
| +
|
| + for(i=0; i<pPk->nKeyCol; i++){
|
| + char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
|
| + x = pPk->aiColumn[i];
|
| + assert( x>=0 );
|
| + if( i==(pPk->nKeyCol-1) ){
|
| + addrJump = addrUniqueOk;
|
| + op = OP_Eq;
|
| + }
|
| + sqlite3VdbeAddOp4(v, op,
|
| + regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
|
| + );
|
| + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
| + VdbeCoverageIf(v, op==OP_Eq);
|
| + VdbeCoverageIf(v, op==OP_Ne);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Generate code that executes if the new index entry is not unique */
|
| + assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|
| + || onError==OE_Ignore || onError==OE_Replace );
|
| + switch( onError ){
|
| + case OE_Rollback:
|
| + case OE_Abort:
|
| + case OE_Fail: {
|
| + sqlite3UniqueConstraint(pParse, onError, pIdx);
|
| + break;
|
| + }
|
| + case OE_Ignore: {
|
| + sqlite3VdbeGoto(v, ignoreDest);
|
| + break;
|
| + }
|
| + default: {
|
| + Trigger *pTrigger = 0;
|
| + assert( onError==OE_Replace );
|
| + sqlite3MultiWrite(pParse);
|
| + if( db->flags&SQLITE_RecTriggers ){
|
| + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
| + }
|
| + sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
| + regR, nPkField, 0, OE_Replace,
|
| + (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1);
|
| + seenReplace = 1;
|
| + break;
|
| + }
|
| + }
|
| + sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
| + sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
| + if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
| + }
|
| + if( ipkTop ){
|
| + sqlite3VdbeGoto(v, ipkTop+1);
|
| + sqlite3VdbeJumpHere(v, ipkBottom);
|
| + }
|
| +
|
| + *pbMayReplace = seenReplace;
|
| + VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
|
| +}
|
| +
|
| +/*
|
| +** This routine generates code to finish the INSERT or UPDATE operation
|
| +** that was started by a prior call to sqlite3GenerateConstraintChecks.
|
| +** A consecutive range of registers starting at regNewData 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 iDataCur, /* Cursor of the canonical data source */
|
| + int iIdxCur, /* First index cursor */
|
| + int regNewData, /* Range of content */
|
| + int *aRegIdx, /* Register used by each index. 0 for unused indices */
|
| + int isUpdate, /* True for UPDATE, False for INSERT */
|
| + int appendBias, /* True if this is likely to be an append */
|
| + int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
|
| +){
|
| + Vdbe *v; /* Prepared statements under construction */
|
| + Index *pIdx; /* An index being inserted or updated */
|
| + u8 pik_flags; /* flag values passed to the btree insert */
|
| + int regData; /* Content registers (after the rowid) */
|
| + int regRec; /* Register holding assembled record for the table */
|
| + int i; /* Loop counter */
|
| + u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
|
| +
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( v!=0 );
|
| + assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
| + for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
| + if( aRegIdx[i]==0 ) continue;
|
| + bAffinityDone = 1;
|
| + if( pIdx->pPartIdxWhere ){
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
| + VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
|
| + pik_flags = 0;
|
| + if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
|
| + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
| + assert( pParse->nested==0 );
|
| + pik_flags |= OPFLAG_NCHANGE;
|
| + }
|
| + if( pik_flags ) sqlite3VdbeChangeP5(v, pik_flags);
|
| + }
|
| + if( !HasRowid(pTab) ) return;
|
| + regData = regNewData + 1;
|
| + regRec = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
|
| + if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0);
|
| + sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
|
| + if( pParse->nested ){
|
| + pik_flags = 0;
|
| + }else{
|
| + pik_flags = OPFLAG_NCHANGE;
|
| + pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
|
| + }
|
| + if( appendBias ){
|
| + pik_flags |= OPFLAG_APPEND;
|
| + }
|
| + if( useSeekResult ){
|
| + pik_flags |= OPFLAG_USESEEKRESULT;
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
|
| + if( !pParse->nested ){
|
| + sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
| + }
|
| + sqlite3VdbeChangeP5(v, pik_flags);
|
| +}
|
| +
|
| +/*
|
| +** Allocate cursors for the pTab table and all its indices and generate
|
| +** code to open and initialized those cursors.
|
| +**
|
| +** The cursor for the object that contains the complete data (normally
|
| +** the table itself, but the PRIMARY KEY index in the case of a WITHOUT
|
| +** ROWID table) is returned in *piDataCur. The first index cursor is
|
| +** returned in *piIdxCur. The number of indices is returned.
|
| +**
|
| +** Use iBase as the first cursor (either the *piDataCur for rowid tables
|
| +** or the first index for WITHOUT ROWID tables) if it is non-negative.
|
| +** If iBase is negative, then allocate the next available cursor.
|
| +**
|
| +** For a rowid table, *piDataCur will be exactly one less than *piIdxCur.
|
| +** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range
|
| +** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the
|
| +** pTab->pIndex list.
|
| +**
|
| +** If pTab is a virtual table, then this routine is a no-op and the
|
| +** *piDataCur and *piIdxCur values are left uninitialized.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
|
| + Parse *pParse, /* Parsing context */
|
| + Table *pTab, /* Table to be opened */
|
| + int op, /* OP_OpenRead or OP_OpenWrite */
|
| + u8 p5, /* P5 value for OP_Open* instructions */
|
| + int iBase, /* Use this for the table cursor, if there is one */
|
| + u8 *aToOpen, /* If not NULL: boolean for each table and index */
|
| + int *piDataCur, /* Write the database source cursor number here */
|
| + int *piIdxCur /* Write the first index cursor number here */
|
| +){
|
| + int i;
|
| + int iDb;
|
| + int iDataCur;
|
| + Index *pIdx;
|
| + Vdbe *v;
|
| +
|
| + assert( op==OP_OpenRead || op==OP_OpenWrite );
|
| + assert( op==OP_OpenWrite || p5==0 );
|
| + if( IsVirtual(pTab) ){
|
| + /* This routine is a no-op for virtual tables. Leave the output
|
| + ** variables *piDataCur and *piIdxCur uninitialized so that valgrind
|
| + ** can detect if they are used by mistake in the caller. */
|
| + return 0;
|
| + }
|
| + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( v!=0 );
|
| + if( iBase<0 ) iBase = pParse->nTab;
|
| + iDataCur = iBase++;
|
| + if( piDataCur ) *piDataCur = iDataCur;
|
| + if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){
|
| + sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op);
|
| + }else{
|
| + sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
|
| + }
|
| + if( piIdxCur ) *piIdxCur = iBase;
|
| + for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
| + int iIdxCur = iBase++;
|
| + assert( pIdx->pSchema==pTab->pSchema );
|
| + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){
|
| + *piDataCur = iIdxCur;
|
| + }
|
| + if( aToOpen==0 || aToOpen[i+1] ){
|
| + sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
|
| + sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
| + sqlite3VdbeChangeP5(v, p5);
|
| + VdbeComment((v, "%s", pIdx->zName));
|
| + }
|
| + }
|
| + if( iBase>pParse->nTab ) pParse->nTab = iBase;
|
| + return i;
|
| +}
|
| +
|
| +
|
| +#ifdef SQLITE_TEST
|
| +/*
|
| +** The following global variable is incremented whenever the
|
| +** transfer optimization is used. This is used for testing
|
| +** purposes only - to make sure the transfer optimization really
|
| +** is happening when it is supposed to.
|
| +*/
|
| +SQLITE_API int sqlite3_xferopt_count;
|
| +#endif /* SQLITE_TEST */
|
| +
|
| +
|
| +#ifndef SQLITE_OMIT_XFER_OPT
|
| +/*
|
| +** Check to see if index pSrc is compatible as a source of data
|
| +** for index pDest in an insert transfer optimization. The rules
|
| +** for a compatible index:
|
| +**
|
| +** * The index is over the same set of columns
|
| +** * The same DESC and ASC markings occurs on all columns
|
| +** * The same onError processing (OE_Abort, OE_Ignore, etc)
|
| +** * The same collating sequence on each column
|
| +** * The index has the exact same WHERE clause
|
| +*/
|
| +static int xferCompatibleIndex(Index *pDest, Index *pSrc){
|
| + int i;
|
| + assert( pDest && pSrc );
|
| + assert( pDest->pTable!=pSrc->pTable );
|
| + if( pDest->nKeyCol!=pSrc->nKeyCol ){
|
| + return 0; /* Different number of columns */
|
| + }
|
| + if( pDest->onError!=pSrc->onError ){
|
| + return 0; /* Different conflict resolution strategies */
|
| + }
|
| + for(i=0; i<pSrc->nKeyCol; i++){
|
| + if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
|
| + return 0; /* Different columns indexed */
|
| + }
|
| + if( pSrc->aiColumn[i]==XN_EXPR ){
|
| + assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
|
| + if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
|
| + pDest->aColExpr->a[i].pExpr, -1)!=0 ){
|
| + return 0; /* Different expressions in the index */
|
| + }
|
| + }
|
| + if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
|
| + return 0; /* Different sort orders */
|
| + }
|
| + if( sqlite3_stricmp(pSrc->azColl[i],pDest->azColl[i])!=0 ){
|
| + return 0; /* Different collating sequences */
|
| + }
|
| + }
|
| + if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
|
| + return 0; /* Different WHERE clauses */
|
| + }
|
| +
|
| + /* If no test above fails then the indices must be compatible */
|
| + return 1;
|
| +}
|
| +
|
| +/*
|
| +** Attempt the transfer optimization on INSERTs of the form
|
| +**
|
| +** INSERT INTO tab1 SELECT * FROM tab2;
|
| +**
|
| +** The xfer optimization transfers raw records from tab2 over to tab1.
|
| +** Columns are not decoded and reassembled, which greatly improves
|
| +** performance. Raw index records are transferred in the same way.
|
| +**
|
| +** The xfer optimization is only attempted if tab1 and tab2 are compatible.
|
| +** There are lots of rules for determining compatibility - see comments
|
| +** embedded in the code for details.
|
| +**
|
| +** This routine returns TRUE if the optimization is guaranteed to be used.
|
| +** Sometimes the xfer optimization will only work if the destination table
|
| +** is empty - a factor that can only be determined at run-time. In that
|
| +** case, this routine generates code for the xfer optimization but also
|
| +** does a test to see if the destination table is empty and jumps over the
|
| +** xfer optimization code if the test fails. In that case, this routine
|
| +** returns FALSE so that the caller will know to go ahead and generate
|
| +** an unoptimized transfer. This routine also returns FALSE if there
|
| +** is no chance that the xfer optimization can be applied.
|
| +**
|
| +** This optimization is particularly useful at making VACUUM run faster.
|
| +*/
|
| +static int xferOptimization(
|
| + Parse *pParse, /* Parser context */
|
| + Table *pDest, /* The table we are inserting into */
|
| + Select *pSelect, /* A SELECT statement to use as the data source */
|
| + int onError, /* How to handle constraint errors */
|
| + int iDbDest /* The database of pDest */
|
| +){
|
| + sqlite3 *db = pParse->db;
|
| + ExprList *pEList; /* The result set of the SELECT */
|
| + Table *pSrc; /* The table in the FROM clause of SELECT */
|
| + Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
|
| + struct SrcList_item *pItem; /* An element of pSelect->pSrc */
|
| + int i; /* Loop counter */
|
| + int iDbSrc; /* The database of pSrc */
|
| + int iSrc, iDest; /* Cursors from source and destination */
|
| + int addr1, addr2; /* Loop addresses */
|
| + int emptyDestTest = 0; /* Address of test for empty pDest */
|
| + int emptySrcTest = 0; /* Address of test for empty pSrc */
|
| + Vdbe *v; /* The VDBE we are building */
|
| + int regAutoinc; /* Memory register used by AUTOINC */
|
| + int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
|
| + int regData, regRowid; /* Registers holding data and rowid */
|
| +
|
| + if( pSelect==0 ){
|
| + return 0; /* Must be of the form INSERT INTO ... SELECT ... */
|
| + }
|
| + if( pParse->pWith || pSelect->pWith ){
|
| + /* Do not attempt to process this query if there are an WITH clauses
|
| + ** attached to it. Proceeding may generate a false "no such table: xxx"
|
| + ** error if pSelect reads from a CTE named "xxx". */
|
| + return 0;
|
| + }
|
| + if( sqlite3TriggerList(pParse, pDest) ){
|
| + return 0; /* tab1 must not have triggers */
|
| + }
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( pDest->tabFlags & TF_Virtual ){
|
| + return 0; /* tab1 must not be a virtual table */
|
| + }
|
| +#endif
|
| + if( onError==OE_Default ){
|
| + if( pDest->iPKey>=0 ) onError = pDest->keyConf;
|
| + if( onError==OE_Default ) onError = OE_Abort;
|
| + }
|
| + assert(pSelect->pSrc); /* allocated even if there is no FROM clause */
|
| + if( pSelect->pSrc->nSrc!=1 ){
|
| + return 0; /* FROM clause must have exactly one term */
|
| + }
|
| + if( pSelect->pSrc->a[0].pSelect ){
|
| + return 0; /* FROM clause cannot contain a subquery */
|
| + }
|
| + if( pSelect->pWhere ){
|
| + return 0; /* SELECT may not have a WHERE clause */
|
| + }
|
| + if( pSelect->pOrderBy ){
|
| + return 0; /* SELECT may not have an ORDER BY clause */
|
| + }
|
| + /* Do not need to test for a HAVING clause. If HAVING is present but
|
| + ** there is no ORDER BY, we will get an error. */
|
| + if( pSelect->pGroupBy ){
|
| + return 0; /* SELECT may not have a GROUP BY clause */
|
| + }
|
| + if( pSelect->pLimit ){
|
| + return 0; /* SELECT may not have a LIMIT clause */
|
| + }
|
| + assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */
|
| + if( pSelect->pPrior ){
|
| + return 0; /* SELECT may not be a compound query */
|
| + }
|
| + if( pSelect->selFlags & SF_Distinct ){
|
| + return 0; /* SELECT may not be DISTINCT */
|
| + }
|
| + pEList = pSelect->pEList;
|
| + assert( pEList!=0 );
|
| + if( pEList->nExpr!=1 ){
|
| + return 0; /* The result set must have exactly one column */
|
| + }
|
| + assert( pEList->a[0].pExpr );
|
| + if( pEList->a[0].pExpr->op!=TK_ASTERISK ){
|
| + return 0; /* The result set must be the special operator "*" */
|
| + }
|
| +
|
| + /* At this point we have established that the statement is of the
|
| + ** correct syntactic form to participate in this optimization. Now
|
| + ** we have to check the semantics.
|
| + */
|
| + pItem = pSelect->pSrc->a;
|
| + pSrc = sqlite3LocateTableItem(pParse, 0, pItem);
|
| + if( pSrc==0 ){
|
| + return 0; /* FROM clause does not contain a real table */
|
| + }
|
| + if( pSrc==pDest ){
|
| + return 0; /* tab1 and tab2 may not be the same table */
|
| + }
|
| + if( HasRowid(pDest)!=HasRowid(pSrc) ){
|
| + return 0; /* source and destination must both be WITHOUT ROWID or not */
|
| + }
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( pSrc->tabFlags & TF_Virtual ){
|
| + return 0; /* tab2 must not be a virtual table */
|
| + }
|
| +#endif
|
| + if( pSrc->pSelect ){
|
| + return 0; /* tab2 may not be a view */
|
| + }
|
| + if( pDest->nCol!=pSrc->nCol ){
|
| + return 0; /* Number of columns must be the same in tab1 and tab2 */
|
| + }
|
| + if( pDest->iPKey!=pSrc->iPKey ){
|
| + return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
|
| + }
|
| + for(i=0; i<pDest->nCol; i++){
|
| + Column *pDestCol = &pDest->aCol[i];
|
| + Column *pSrcCol = &pSrc->aCol[i];
|
| +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
|
| + if( (db->flags & SQLITE_Vacuum)==0
|
| + && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
|
| + ){
|
| + return 0; /* Neither table may have __hidden__ columns */
|
| + }
|
| +#endif
|
| + if( pDestCol->affinity!=pSrcCol->affinity ){
|
| + return 0; /* Affinity must be the same on all columns */
|
| + }
|
| + if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){
|
| + return 0; /* Collating sequence must be the same on all columns */
|
| + }
|
| + if( pDestCol->notNull && !pSrcCol->notNull ){
|
| + return 0; /* tab2 must be NOT NULL if tab1 is */
|
| + }
|
| + /* Default values for second and subsequent columns need to match. */
|
| + if( i>0
|
| + && ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|
| + || (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
|
| + ){
|
| + return 0; /* Default values must be the same for all columns */
|
| + }
|
| + }
|
| + for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
| + if( IsUniqueIndex(pDestIdx) ){
|
| + destHasUniqueIdx = 1;
|
| + }
|
| + for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
|
| + if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
| + }
|
| + if( pSrcIdx==0 ){
|
| + return 0; /* pDestIdx has no corresponding index in pSrc */
|
| + }
|
| + }
|
| +#ifndef SQLITE_OMIT_CHECK
|
| + if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){
|
| + return 0; /* Tables have different CHECK constraints. Ticket #2252 */
|
| + }
|
| +#endif
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| + /* Disallow the transfer optimization if the destination table constains
|
| + ** any foreign key constraints. This is more restrictive than necessary.
|
| + ** But the main beneficiary of the transfer optimization is the VACUUM
|
| + ** command, and the VACUUM command disables foreign key constraints. So
|
| + ** the extra complication to make this rule less restrictive is probably
|
| + ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
|
| + */
|
| + if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
|
| + return 0;
|
| + }
|
| +#endif
|
| + if( (db->flags & SQLITE_CountRows)!=0 ){
|
| + return 0; /* xfer opt does not play well with PRAGMA count_changes */
|
| + }
|
| +
|
| + /* If we get this far, it means that the xfer optimization is at
|
| + ** least a possibility, though it might only work if the destination
|
| + ** table (tab1) is initially empty.
|
| + */
|
| +#ifdef SQLITE_TEST
|
| + sqlite3_xferopt_count++;
|
| +#endif
|
| + iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema);
|
| + v = sqlite3GetVdbe(pParse);
|
| + sqlite3CodeVerifySchema(pParse, iDbSrc);
|
| + iSrc = pParse->nTab++;
|
| + iDest = pParse->nTab++;
|
| + regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
|
| + regData = sqlite3GetTempReg(pParse);
|
| + regRowid = sqlite3GetTempReg(pParse);
|
| + sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
| + assert( HasRowid(pDest) || destHasUniqueIdx );
|
| + if( (db->flags & SQLITE_Vacuum)==0 && (
|
| + (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|
| + || destHasUniqueIdx /* (2) */
|
| + || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
|
| + )){
|
| + /* In some circumstances, we are able to run the xfer optimization
|
| + ** only if the destination table is initially empty. Unless the
|
| + ** SQLITE_Vacuum flag is set, this block generates code to make
|
| + ** that determination. If SQLITE_Vacuum is set, then the destination
|
| + ** table is always empty.
|
| + **
|
| + ** Conditions under which the destination must be empty:
|
| + **
|
| + ** (1) There is no INTEGER PRIMARY KEY but there are indices.
|
| + ** (If the destination is not initially empty, the rowid fields
|
| + ** of index entries might need to change.)
|
| + **
|
| + ** (2) The destination has a unique index. (The xfer optimization
|
| + ** is unable to test uniqueness.)
|
| + **
|
| + ** (3) onError is something other than OE_Abort and OE_Rollback.
|
| + */
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v);
|
| + emptyDestTest = sqlite3VdbeAddOp0(v, OP_Goto);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + }
|
| + if( HasRowid(pSrc) ){
|
| + sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
|
| + emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
| + if( pDest->iPKey>=0 ){
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
| + addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
| + VdbeCoverage(v);
|
| + sqlite3RowidConstraint(pParse, onError, pDest);
|
| + sqlite3VdbeJumpHere(v, addr2);
|
| + autoIncStep(pParse, regAutoinc, regRowid);
|
| + }else if( pDest->pIndex==0 ){
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
|
| + }else{
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
| + assert( (pDest->tabFlags & TF_Autoincrement)==0 );
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
|
| + sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
|
| + sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
| + sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
| + }else{
|
| + sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName);
|
| + sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName);
|
| + }
|
| + for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
| + u8 idxInsFlags = 0;
|
| + for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
|
| + if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
| + }
|
| + assert( pSrcIdx );
|
| + sqlite3VdbeAddOp3(v, OP_OpenRead, iSrc, pSrcIdx->tnum, iDbSrc);
|
| + sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx);
|
| + VdbeComment((v, "%s", pSrcIdx->zName));
|
| + sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest);
|
| + sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
|
| + VdbeComment((v, "%s", pDestIdx->zName));
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
|
| + if( db->flags & SQLITE_Vacuum ){
|
| + /* This INSERT command is part of a VACUUM operation, which guarantees
|
| + ** that the destination table is empty. If all indexed columns use
|
| + ** collation sequence BINARY, then it can also be assumed that the
|
| + ** index will be populated by inserting keys in strictly sorted
|
| + ** order. In this case, instead of seeking within the b-tree as part
|
| + ** of every OP_IdxInsert opcode, an OP_Last is added before the
|
| + ** OP_IdxInsert to seek to the point within the b-tree where each key
|
| + ** should be inserted. This is faster.
|
| + **
|
| + ** If any of the indexed columns use a collation sequence other than
|
| + ** BINARY, this optimization is disabled. This is because the user
|
| + ** might change the definition of a collation sequence and then run
|
| + ** a VACUUM command. In that case keys may not be written in strictly
|
| + ** sorted order. */
|
| + for(i=0; i<pSrcIdx->nColumn; i++){
|
| + const char *zColl = pSrcIdx->azColl[i];
|
| + assert( sqlite3_stricmp(sqlite3StrBINARY, zColl)!=0
|
| + || sqlite3StrBINARY==zColl );
|
| + if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
|
| + }
|
| + if( i==pSrcIdx->nColumn ){
|
| + idxInsFlags = OPFLAG_USESEEKRESULT;
|
| + sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
|
| + }
|
| + }
|
| + if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
|
| + idxInsFlags |= OPFLAG_NCHANGE;
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
|
| + sqlite3VdbeChangeP5(v, idxInsFlags);
|
| + sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
| + sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
| + }
|
| + if( emptySrcTest ) sqlite3VdbeJumpHere(v, emptySrcTest);
|
| + sqlite3ReleaseTempReg(pParse, regRowid);
|
| + sqlite3ReleaseTempReg(pParse, regData);
|
| + if( emptyDestTest ){
|
| + sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0);
|
| + sqlite3VdbeJumpHere(v, emptyDestTest);
|
| + sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
| + return 0;
|
| + }else{
|
| + return 1;
|
| + }
|
| +}
|
| +#endif /* SQLITE_OMIT_XFER_OPT */
|
| +
|
| +/************** End of insert.c **********************************************/
|
| +/************** Begin file legacy.c ******************************************/
|
| +/*
|
| +** 2001 September 15
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** Main file for the SQLite library. The routines in this file
|
| +** implement the programmer interface to the library. Routines in
|
| +** other files are for internal use by SQLite and should not be
|
| +** accessed by users of the library.
|
| +*/
|
| +
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +/*
|
| +** Execute SQL code. Return one of the SQLITE_ success/failure
|
| +** codes. Also write an error message into memory obtained from
|
| +** malloc() and make *pzErrMsg point to that message.
|
| +**
|
| +** If the SQL is a query, then for each row in the query result
|
| +** the xCallback() function is called. pArg becomes the first
|
| +** argument to xCallback(). If xCallback=NULL then no callback
|
| +** is invoked, even for queries.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_exec(
|
| + sqlite3 *db, /* The database on which the SQL executes */
|
| + const char *zSql, /* The SQL to be executed */
|
| + sqlite3_callback xCallback, /* Invoke this callback routine */
|
| + void *pArg, /* First argument to xCallback() */
|
| + char **pzErrMsg /* Write error messages here */
|
| +){
|
| + int rc = SQLITE_OK; /* Return code */
|
| + const char *zLeftover; /* Tail of unprocessed SQL */
|
| + sqlite3_stmt *pStmt = 0; /* The current SQL statement */
|
| + char **azCols = 0; /* Names of result columns */
|
| + int callbackIsInit; /* True if callback data is initialized */
|
| +
|
| + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
| + if( zSql==0 ) zSql = "";
|
| +
|
| + sqlite3_mutex_enter(db->mutex);
|
| + sqlite3Error(db, SQLITE_OK);
|
| + while( rc==SQLITE_OK && zSql[0] ){
|
| + int nCol;
|
| + char **azVals = 0;
|
| +
|
| + pStmt = 0;
|
| + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
|
| + assert( rc==SQLITE_OK || pStmt==0 );
|
| + if( rc!=SQLITE_OK ){
|
| + continue;
|
| + }
|
| + if( !pStmt ){
|
| + /* this happens for a comment or white-space */
|
| + zSql = zLeftover;
|
| + continue;
|
| + }
|
| +
|
| + callbackIsInit = 0;
|
| + nCol = sqlite3_column_count(pStmt);
|
| +
|
| + while( 1 ){
|
| + int i;
|
| + rc = sqlite3_step(pStmt);
|
| +
|
| + /* Invoke the callback function if required */
|
| + if( xCallback && (SQLITE_ROW==rc ||
|
| + (SQLITE_DONE==rc && !callbackIsInit
|
| + && db->flags&SQLITE_NullCallback)) ){
|
| + if( !callbackIsInit ){
|
| + azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char*) + 1);
|
| + if( azCols==0 ){
|
| + goto exec_out;
|
| + }
|
| + for(i=0; i<nCol; i++){
|
| + azCols[i] = (char *)sqlite3_column_name(pStmt, i);
|
| + /* sqlite3VdbeSetColName() installs column names as UTF8
|
| + ** strings so there is no way for sqlite3_column_name() to fail. */
|
| + assert( azCols[i]!=0 );
|
| + }
|
| + callbackIsInit = 1;
|
| + }
|
| + if( rc==SQLITE_ROW ){
|
| + azVals = &azCols[nCol];
|
| + for(i=0; i<nCol; i++){
|
| + azVals[i] = (char *)sqlite3_column_text(pStmt, i);
|
| + if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
|
| + db->mallocFailed = 1;
|
| + goto exec_out;
|
| + }
|
| + }
|
| + }
|
| + if( xCallback(pArg, nCol, azVals, azCols) ){
|
| + /* EVIDENCE-OF: R-38229-40159 If the callback function to
|
| + ** sqlite3_exec() returns non-zero, then sqlite3_exec() will
|
| + ** return SQLITE_ABORT. */
|
| + rc = SQLITE_ABORT;
|
| + sqlite3VdbeFinalize((Vdbe *)pStmt);
|
| + pStmt = 0;
|
| + sqlite3Error(db, SQLITE_ABORT);
|
| + goto exec_out;
|
| + }
|
| + }
|
| +
|
| + if( rc!=SQLITE_ROW ){
|
| + rc = sqlite3VdbeFinalize((Vdbe *)pStmt);
|
| + pStmt = 0;
|
| + zSql = zLeftover;
|
| + while( sqlite3Isspace(zSql[0]) ) zSql++;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + sqlite3DbFree(db, azCols);
|
| + azCols = 0;
|
| + }
|
| +
|
| +exec_out:
|
| + if( pStmt ) sqlite3VdbeFinalize((Vdbe *)pStmt);
|
| + sqlite3DbFree(db, azCols);
|
| +
|
| + rc = sqlite3ApiExit(db, rc);
|
| + if( rc!=SQLITE_OK && pzErrMsg ){
|
| + int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
|
| + *pzErrMsg = sqlite3Malloc(nErrMsg);
|
| + if( *pzErrMsg ){
|
| + memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
|
| + }else{
|
| + rc = SQLITE_NOMEM;
|
| + sqlite3Error(db, SQLITE_NOMEM);
|
| + }
|
| + }else if( pzErrMsg ){
|
| + *pzErrMsg = 0;
|
| + }
|
| +
|
| + assert( (rc&db->errMask)==rc );
|
| + sqlite3_mutex_leave(db->mutex);
|
| + return rc;
|
| +}
|
| +
|
| +/************** End of legacy.c **********************************************/
|
| +/************** Begin file loadext.c *****************************************/
|
| +/*
|
| +** 2006 June 7
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains code used to dynamically load extensions into
|
| +** the SQLite library.
|
| +*/
|
| +
|
| +#ifndef SQLITE_CORE
|
| + #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
|
| +#endif
|
| +/************** Include sqlite3ext.h in the middle of loadext.c **************/
|
| +/************** Begin file sqlite3ext.h **************************************/
|
| +/*
|
| +** 2006 June 7
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This header file defines the SQLite interface for use by
|
| +** shared libraries that want to be imported as extensions into
|
| +** an SQLite instance. Shared libraries that intend to be loaded
|
| +** as extensions by SQLite should #include this file instead of
|
| +** sqlite3.h.
|
| +*/
|
| +#ifndef _SQLITE3EXT_H_
|
| +#define _SQLITE3EXT_H_
|
| +/* #include "sqlite3.h" */
|
| +
|
| +typedef struct sqlite3_api_routines sqlite3_api_routines;
|
| +
|
| +/*
|
| +** The following structure holds pointers to all of the SQLite API
|
| +** routines.
|
| +**
|
| +** WARNING: In order to maintain backwards compatibility, add new
|
| +** interfaces to the end of this structure only. If you insert new
|
| +** interfaces in the middle of this structure, then older different
|
| +** versions of SQLite will not be able to load each other's shared
|
| +** libraries!
|
| +*/
|
| +struct sqlite3_api_routines {
|
| + void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
| + int (*aggregate_count)(sqlite3_context*);
|
| + int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
| + int (*bind_double)(sqlite3_stmt*,int,double);
|
| + int (*bind_int)(sqlite3_stmt*,int,int);
|
| + int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
| + int (*bind_null)(sqlite3_stmt*,int);
|
| + int (*bind_parameter_count)(sqlite3_stmt*);
|
| + int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
| + const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
| + int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
| + int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
| + int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
| + int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
| + int (*busy_timeout)(sqlite3*,int ms);
|
| + int (*changes)(sqlite3*);
|
| + int (*close)(sqlite3*);
|
| + int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
| + int eTextRep,const char*));
|
| + int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
| + int eTextRep,const void*));
|
| + const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
| + int (*column_bytes)(sqlite3_stmt*,int iCol);
|
| + int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
| + int (*column_count)(sqlite3_stmt*pStmt);
|
| + const char * (*column_database_name)(sqlite3_stmt*,int);
|
| + const void * (*column_database_name16)(sqlite3_stmt*,int);
|
| + const char * (*column_decltype)(sqlite3_stmt*,int i);
|
| + const void * (*column_decltype16)(sqlite3_stmt*,int);
|
| + double (*column_double)(sqlite3_stmt*,int iCol);
|
| + int (*column_int)(sqlite3_stmt*,int iCol);
|
| + sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
| + const char * (*column_name)(sqlite3_stmt*,int);
|
| + const void * (*column_name16)(sqlite3_stmt*,int);
|
| + const char * (*column_origin_name)(sqlite3_stmt*,int);
|
| + const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
| + const char * (*column_table_name)(sqlite3_stmt*,int);
|
| + const void * (*column_table_name16)(sqlite3_stmt*,int);
|
| + const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
| + const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
| + int (*column_type)(sqlite3_stmt*,int iCol);
|
| + sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
| + void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
| + int (*complete)(const char*sql);
|
| + int (*complete16)(const void*sql);
|
| + int (*create_collation)(sqlite3*,const char*,int,void*,
|
| + int(*)(void*,int,const void*,int,const void*));
|
| + int (*create_collation16)(sqlite3*,const void*,int,void*,
|
| + int(*)(void*,int,const void*,int,const void*));
|
| + int (*create_function)(sqlite3*,const char*,int,int,void*,
|
| + void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
| + void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
| + void (*xFinal)(sqlite3_context*));
|
| + int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
| + void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
| + void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
| + void (*xFinal)(sqlite3_context*));
|
| + int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
| + int (*data_count)(sqlite3_stmt*pStmt);
|
| + sqlite3 * (*db_handle)(sqlite3_stmt*);
|
| + int (*declare_vtab)(sqlite3*,const char*);
|
| + int (*enable_shared_cache)(int);
|
| + int (*errcode)(sqlite3*db);
|
| + const char * (*errmsg)(sqlite3*);
|
| + const void * (*errmsg16)(sqlite3*);
|
| + int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
| + int (*expired)(sqlite3_stmt*);
|
| + int (*finalize)(sqlite3_stmt*pStmt);
|
| + void (*free)(void*);
|
| + void (*free_table)(char**result);
|
| + int (*get_autocommit)(sqlite3*);
|
| + void * (*get_auxdata)(sqlite3_context*,int);
|
| + int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
| + int (*global_recover)(void);
|
| + void (*interruptx)(sqlite3*);
|
| + sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
| + const char * (*libversion)(void);
|
| + int (*libversion_number)(void);
|
| + void *(*malloc)(int);
|
| + char * (*mprintf)(const char*,...);
|
| + int (*open)(const char*,sqlite3**);
|
| + int (*open16)(const void*,sqlite3**);
|
| + int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
| + int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
| + void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
| + void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
| + void *(*realloc)(void*,int);
|
| + int (*reset)(sqlite3_stmt*pStmt);
|
| + void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
| + void (*result_double)(sqlite3_context*,double);
|
| + void (*result_error)(sqlite3_context*,const char*,int);
|
| + void (*result_error16)(sqlite3_context*,const void*,int);
|
| + void (*result_int)(sqlite3_context*,int);
|
| + void (*result_int64)(sqlite3_context*,sqlite_int64);
|
| + void (*result_null)(sqlite3_context*);
|
| + void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
| + void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
| + void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
| + void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
| + void (*result_value)(sqlite3_context*,sqlite3_value*);
|
| + void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
| + int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
| + const char*,const char*),void*);
|
| + void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
| + char * (*snprintf)(int,char*,const char*,...);
|
| + int (*step)(sqlite3_stmt*);
|
| + int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
| + char const**,char const**,int*,int*,int*);
|
| + void (*thread_cleanup)(void);
|
| + int (*total_changes)(sqlite3*);
|
| + void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
| + int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
| + void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
| + sqlite_int64),void*);
|
| + void * (*user_data)(sqlite3_context*);
|
| + const void * (*value_blob)(sqlite3_value*);
|
| + int (*value_bytes)(sqlite3_value*);
|
| + int (*value_bytes16)(sqlite3_value*);
|
| + double (*value_double)(sqlite3_value*);
|
| + int (*value_int)(sqlite3_value*);
|
| + sqlite_int64 (*value_int64)(sqlite3_value*);
|
| + int (*value_numeric_type)(sqlite3_value*);
|
| + const unsigned char * (*value_text)(sqlite3_value*);
|
| + const void * (*value_text16)(sqlite3_value*);
|
| + const void * (*value_text16be)(sqlite3_value*);
|
| + const void * (*value_text16le)(sqlite3_value*);
|
| + int (*value_type)(sqlite3_value*);
|
| + char *(*vmprintf)(const char*,va_list);
|
| + /* Added ??? */
|
| + int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
| + /* Added by 3.3.13 */
|
| + int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
| + int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
| + int (*clear_bindings)(sqlite3_stmt*);
|
| + /* Added by 3.4.1 */
|
| + int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
| + void (*xDestroy)(void *));
|
| + /* Added by 3.5.0 */
|
| + int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
| + int (*blob_bytes)(sqlite3_blob*);
|
| + int (*blob_close)(sqlite3_blob*);
|
| + int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
| + int,sqlite3_blob**);
|
| + int (*blob_read)(sqlite3_blob*,void*,int,int);
|
| + int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
| + int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
| + int(*)(void*,int,const void*,int,const void*),
|
| + void(*)(void*));
|
| + int (*file_control)(sqlite3*,const char*,int,void*);
|
| + sqlite3_int64 (*memory_highwater)(int);
|
| + sqlite3_int64 (*memory_used)(void);
|
| + sqlite3_mutex *(*mutex_alloc)(int);
|
| + void (*mutex_enter)(sqlite3_mutex*);
|
| + void (*mutex_free)(sqlite3_mutex*);
|
| + void (*mutex_leave)(sqlite3_mutex*);
|
| + int (*mutex_try)(sqlite3_mutex*);
|
| + int (*open_v2)(const char*,sqlite3**,int,const char*);
|
| + int (*release_memory)(int);
|
| + void (*result_error_nomem)(sqlite3_context*);
|
| + void (*result_error_toobig)(sqlite3_context*);
|
| + int (*sleep)(int);
|
| + void (*soft_heap_limit)(int);
|
| + sqlite3_vfs *(*vfs_find)(const char*);
|
| + int (*vfs_register)(sqlite3_vfs*,int);
|
| + int (*vfs_unregister)(sqlite3_vfs*);
|
| + int (*xthreadsafe)(void);
|
| + void (*result_zeroblob)(sqlite3_context*,int);
|
| + void (*result_error_code)(sqlite3_context*,int);
|
| + int (*test_control)(int, ...);
|
| + void (*randomness)(int,void*);
|
| + sqlite3 *(*context_db_handle)(sqlite3_context*);
|
| + int (*extended_result_codes)(sqlite3*,int);
|
| + int (*limit)(sqlite3*,int,int);
|
| + sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
| + const char *(*sql)(sqlite3_stmt*);
|
| + int (*status)(int,int*,int*,int);
|
| + int (*backup_finish)(sqlite3_backup*);
|
| + sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
| + int (*backup_pagecount)(sqlite3_backup*);
|
| + int (*backup_remaining)(sqlite3_backup*);
|
| + int (*backup_step)(sqlite3_backup*,int);
|
| + const char *(*compileoption_get)(int);
|
| + int (*compileoption_used)(const char*);
|
| + int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
| + void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
| + void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
| + void (*xFinal)(sqlite3_context*),
|
| + void(*xDestroy)(void*));
|
| + int (*db_config)(sqlite3*,int,...);
|
| + sqlite3_mutex *(*db_mutex)(sqlite3*);
|
| + int (*db_status)(sqlite3*,int,int*,int*,int);
|
| + int (*extended_errcode)(sqlite3*);
|
| + void (*log)(int,const char*,...);
|
| + sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
| + const char *(*sourceid)(void);
|
| + int (*stmt_status)(sqlite3_stmt*,int,int);
|
| + int (*strnicmp)(const char*,const char*,int);
|
| + int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
| + int (*wal_autocheckpoint)(sqlite3*,int);
|
| + int (*wal_checkpoint)(sqlite3*,const char*);
|
| + void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
| + int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
| + int (*vtab_config)(sqlite3*,int op,...);
|
| + int (*vtab_on_conflict)(sqlite3*);
|
| + /* Version 3.7.16 and later */
|
| + int (*close_v2)(sqlite3*);
|
| + const char *(*db_filename)(sqlite3*,const char*);
|
| + int (*db_readonly)(sqlite3*,const char*);
|
| + int (*db_release_memory)(sqlite3*);
|
| + const char *(*errstr)(int);
|
| + int (*stmt_busy)(sqlite3_stmt*);
|
| + int (*stmt_readonly)(sqlite3_stmt*);
|
| + int (*stricmp)(const char*,const char*);
|
| + int (*uri_boolean)(const char*,const char*,int);
|
| + sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
| + const char *(*uri_parameter)(const char*,const char*);
|
| + char *(*vsnprintf)(int,char*,const char*,va_list);
|
| + int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
| + /* Version 3.8.7 and later */
|
| + int (*auto_extension)(void(*)(void));
|
| + int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
| + void(*)(void*));
|
| + int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
| + void(*)(void*),unsigned char);
|
| + int (*cancel_auto_extension)(void(*)(void));
|
| + int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
| + void *(*malloc64)(sqlite3_uint64);
|
| + sqlite3_uint64 (*msize)(void*);
|
| + void *(*realloc64)(void*,sqlite3_uint64);
|
| + void (*reset_auto_extension)(void);
|
| + void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
| + void(*)(void*));
|
| + void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
| + void(*)(void*), unsigned char);
|
| + int (*strglob)(const char*,const char*);
|
| + /* Version 3.8.11 and later */
|
| + sqlite3_value *(*value_dup)(const sqlite3_value*);
|
| + void (*value_free)(sqlite3_value*);
|
| + int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
| + int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
| + /* Version 3.9.0 and later */
|
| + unsigned int (*value_subtype)(sqlite3_value*);
|
| + void (*result_subtype)(sqlite3_context*,unsigned int);
|
| + /* Version 3.10.0 and later */
|
| + int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
| + int (*strlike)(const char*,const char*,unsigned int);
|
| + int (*db_cacheflush)(sqlite3*);
|
| +};
|
| +
|
| +/*
|
| +** The following macros redefine the API routines so that they are
|
| +** redirected through the global sqlite3_api structure.
|
| +**
|
| +** This header file is also used by the loadext.c source file
|
| +** (part of the main SQLite library - not an extension) so that
|
| +** it can get access to the sqlite3_api_routines structure
|
| +** definition. But the main library does not want to redefine
|
| +** the API. So the redefinition macros are only valid if the
|
| +** SQLITE_CORE macros is undefined.
|
| +*/
|
| +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
| +#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| +#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
| +#endif
|
| +#define sqlite3_bind_blob sqlite3_api->bind_blob
|
| +#define sqlite3_bind_double sqlite3_api->bind_double
|
| +#define sqlite3_bind_int sqlite3_api->bind_int
|
| +#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
| +#define sqlite3_bind_null sqlite3_api->bind_null
|
| +#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
| +#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
| +#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
| +#define sqlite3_bind_text sqlite3_api->bind_text
|
| +#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
| +#define sqlite3_bind_value sqlite3_api->bind_value
|
| +#define sqlite3_busy_handler sqlite3_api->busy_handler
|
| +#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
| +#define sqlite3_changes sqlite3_api->changes
|
| +#define sqlite3_close sqlite3_api->close
|
| +#define sqlite3_collation_needed sqlite3_api->collation_needed
|
| +#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
| +#define sqlite3_column_blob sqlite3_api->column_blob
|
| +#define sqlite3_column_bytes sqlite3_api->column_bytes
|
| +#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
| +#define sqlite3_column_count sqlite3_api->column_count
|
| +#define sqlite3_column_database_name sqlite3_api->column_database_name
|
| +#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
| +#define sqlite3_column_decltype sqlite3_api->column_decltype
|
| +#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
| +#define sqlite3_column_double sqlite3_api->column_double
|
| +#define sqlite3_column_int sqlite3_api->column_int
|
| +#define sqlite3_column_int64 sqlite3_api->column_int64
|
| +#define sqlite3_column_name sqlite3_api->column_name
|
| +#define sqlite3_column_name16 sqlite3_api->column_name16
|
| +#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
| +#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
| +#define sqlite3_column_table_name sqlite3_api->column_table_name
|
| +#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
| +#define sqlite3_column_text sqlite3_api->column_text
|
| +#define sqlite3_column_text16 sqlite3_api->column_text16
|
| +#define sqlite3_column_type sqlite3_api->column_type
|
| +#define sqlite3_column_value sqlite3_api->column_value
|
| +#define sqlite3_commit_hook sqlite3_api->commit_hook
|
| +#define sqlite3_complete sqlite3_api->complete
|
| +#define sqlite3_complete16 sqlite3_api->complete16
|
| +#define sqlite3_create_collation sqlite3_api->create_collation
|
| +#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
| +#define sqlite3_create_function sqlite3_api->create_function
|
| +#define sqlite3_create_function16 sqlite3_api->create_function16
|
| +#define sqlite3_create_module sqlite3_api->create_module
|
| +#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
| +#define sqlite3_data_count sqlite3_api->data_count
|
| +#define sqlite3_db_handle sqlite3_api->db_handle
|
| +#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
| +#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
| +#define sqlite3_errcode sqlite3_api->errcode
|
| +#define sqlite3_errmsg sqlite3_api->errmsg
|
| +#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
| +#define sqlite3_exec sqlite3_api->exec
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| +#define sqlite3_expired sqlite3_api->expired
|
| +#endif
|
| +#define sqlite3_finalize sqlite3_api->finalize
|
| +#define sqlite3_free sqlite3_api->free
|
| +#define sqlite3_free_table sqlite3_api->free_table
|
| +#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
| +#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
| +#define sqlite3_get_table sqlite3_api->get_table
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| +#define sqlite3_global_recover sqlite3_api->global_recover
|
| +#endif
|
| +#define sqlite3_interrupt sqlite3_api->interruptx
|
| +#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
| +#define sqlite3_libversion sqlite3_api->libversion
|
| +#define sqlite3_libversion_number sqlite3_api->libversion_number
|
| +#define sqlite3_malloc sqlite3_api->malloc
|
| +#define sqlite3_mprintf sqlite3_api->mprintf
|
| +#define sqlite3_open sqlite3_api->open
|
| +#define sqlite3_open16 sqlite3_api->open16
|
| +#define sqlite3_prepare sqlite3_api->prepare
|
| +#define sqlite3_prepare16 sqlite3_api->prepare16
|
| +#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
| +#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
| +#define sqlite3_profile sqlite3_api->profile
|
| +#define sqlite3_progress_handler sqlite3_api->progress_handler
|
| +#define sqlite3_realloc sqlite3_api->realloc
|
| +#define sqlite3_reset sqlite3_api->reset
|
| +#define sqlite3_result_blob sqlite3_api->result_blob
|
| +#define sqlite3_result_double sqlite3_api->result_double
|
| +#define sqlite3_result_error sqlite3_api->result_error
|
| +#define sqlite3_result_error16 sqlite3_api->result_error16
|
| +#define sqlite3_result_int sqlite3_api->result_int
|
| +#define sqlite3_result_int64 sqlite3_api->result_int64
|
| +#define sqlite3_result_null sqlite3_api->result_null
|
| +#define sqlite3_result_text sqlite3_api->result_text
|
| +#define sqlite3_result_text16 sqlite3_api->result_text16
|
| +#define sqlite3_result_text16be sqlite3_api->result_text16be
|
| +#define sqlite3_result_text16le sqlite3_api->result_text16le
|
| +#define sqlite3_result_value sqlite3_api->result_value
|
| +#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
| +#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
| +#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
| +#define sqlite3_snprintf sqlite3_api->snprintf
|
| +#define sqlite3_step sqlite3_api->step
|
| +#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
| +#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
| +#define sqlite3_total_changes sqlite3_api->total_changes
|
| +#define sqlite3_trace sqlite3_api->trace
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| +#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
| +#endif
|
| +#define sqlite3_update_hook sqlite3_api->update_hook
|
| +#define sqlite3_user_data sqlite3_api->user_data
|
| +#define sqlite3_value_blob sqlite3_api->value_blob
|
| +#define sqlite3_value_bytes sqlite3_api->value_bytes
|
| +#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
| +#define sqlite3_value_double sqlite3_api->value_double
|
| +#define sqlite3_value_int sqlite3_api->value_int
|
| +#define sqlite3_value_int64 sqlite3_api->value_int64
|
| +#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
| +#define sqlite3_value_text sqlite3_api->value_text
|
| +#define sqlite3_value_text16 sqlite3_api->value_text16
|
| +#define sqlite3_value_text16be sqlite3_api->value_text16be
|
| +#define sqlite3_value_text16le sqlite3_api->value_text16le
|
| +#define sqlite3_value_type sqlite3_api->value_type
|
| +#define sqlite3_vmprintf sqlite3_api->vmprintf
|
| +#define sqlite3_vsnprintf sqlite3_api->vsnprintf
|
| +#define sqlite3_overload_function sqlite3_api->overload_function
|
| +#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
| +#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
| +#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
| +#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
| +#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
| +#define sqlite3_blob_close sqlite3_api->blob_close
|
| +#define sqlite3_blob_open sqlite3_api->blob_open
|
| +#define sqlite3_blob_read sqlite3_api->blob_read
|
| +#define sqlite3_blob_write sqlite3_api->blob_write
|
| +#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
| +#define sqlite3_file_control sqlite3_api->file_control
|
| +#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
| +#define sqlite3_memory_used sqlite3_api->memory_used
|
| +#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
| +#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
| +#define sqlite3_mutex_free sqlite3_api->mutex_free
|
| +#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
| +#define sqlite3_mutex_try sqlite3_api->mutex_try
|
| +#define sqlite3_open_v2 sqlite3_api->open_v2
|
| +#define sqlite3_release_memory sqlite3_api->release_memory
|
| +#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
| +#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
| +#define sqlite3_sleep sqlite3_api->sleep
|
| +#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
| +#define sqlite3_vfs_find sqlite3_api->vfs_find
|
| +#define sqlite3_vfs_register sqlite3_api->vfs_register
|
| +#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
| +#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
| +#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
| +#define sqlite3_result_error_code sqlite3_api->result_error_code
|
| +#define sqlite3_test_control sqlite3_api->test_control
|
| +#define sqlite3_randomness sqlite3_api->randomness
|
| +#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
| +#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
| +#define sqlite3_limit sqlite3_api->limit
|
| +#define sqlite3_next_stmt sqlite3_api->next_stmt
|
| +#define sqlite3_sql sqlite3_api->sql
|
| +#define sqlite3_status sqlite3_api->status
|
| +#define sqlite3_backup_finish sqlite3_api->backup_finish
|
| +#define sqlite3_backup_init sqlite3_api->backup_init
|
| +#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
| +#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
| +#define sqlite3_backup_step sqlite3_api->backup_step
|
| +#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
| +#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
| +#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
| +#define sqlite3_db_config sqlite3_api->db_config
|
| +#define sqlite3_db_mutex sqlite3_api->db_mutex
|
| +#define sqlite3_db_status sqlite3_api->db_status
|
| +#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
| +#define sqlite3_log sqlite3_api->log
|
| +#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
| +#define sqlite3_sourceid sqlite3_api->sourceid
|
| +#define sqlite3_stmt_status sqlite3_api->stmt_status
|
| +#define sqlite3_strnicmp sqlite3_api->strnicmp
|
| +#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
| +#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
| +#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
| +#define sqlite3_wal_hook sqlite3_api->wal_hook
|
| +#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
| +#define sqlite3_vtab_config sqlite3_api->vtab_config
|
| +#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
| +/* Version 3.7.16 and later */
|
| +#define sqlite3_close_v2 sqlite3_api->close_v2
|
| +#define sqlite3_db_filename sqlite3_api->db_filename
|
| +#define sqlite3_db_readonly sqlite3_api->db_readonly
|
| +#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
| +#define sqlite3_errstr sqlite3_api->errstr
|
| +#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
| +#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
| +#define sqlite3_stricmp sqlite3_api->stricmp
|
| +#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
| +#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
| +#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
| +#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
|
| +#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
| +/* Version 3.8.7 and later */
|
| +#define sqlite3_auto_extension sqlite3_api->auto_extension
|
| +#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
| +#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
| +#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
| +#define sqlite3_load_extension sqlite3_api->load_extension
|
| +#define sqlite3_malloc64 sqlite3_api->malloc64
|
| +#define sqlite3_msize sqlite3_api->msize
|
| +#define sqlite3_realloc64 sqlite3_api->realloc64
|
| +#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
| +#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
| +#define sqlite3_result_text64 sqlite3_api->result_text64
|
| +#define sqlite3_strglob sqlite3_api->strglob
|
| +/* Version 3.8.11 and later */
|
| +#define sqlite3_value_dup sqlite3_api->value_dup
|
| +#define sqlite3_value_free sqlite3_api->value_free
|
| +#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
| +#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
| +/* Version 3.9.0 and later */
|
| +#define sqlite3_value_subtype sqlite3_api->value_subtype
|
| +#define sqlite3_result_subtype sqlite3_api->result_subtype
|
| +/* Version 3.10.0 and later */
|
| +#define sqlite3_status64 sqlite3_api->status64
|
| +#define sqlite3_strlike sqlite3_api->strlike
|
| +#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
| +#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
| +
|
| +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
| + /* This case when the file really is being compiled as a loadable
|
| + ** extension */
|
| +# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
| +# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
| +# define SQLITE_EXTENSION_INIT3 \
|
| + extern const sqlite3_api_routines *sqlite3_api;
|
| +#else
|
| + /* This case when the file is being statically linked into the
|
| + ** application */
|
| +# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
| +# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
| +# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
| +#endif
|
| +
|
| +#endif /* _SQLITE3EXT_H_ */
|
| +
|
| +/************** End of sqlite3ext.h ******************************************/
|
| +/************** Continuing where we left off in loadext.c ********************/
|
| +/* #include "sqliteInt.h" */
|
| +/* #include <string.h> */
|
| +
|
| +#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
| +
|
| +/*
|
| +** Some API routines are omitted when various features are
|
| +** excluded from a build of SQLite. Substitute a NULL pointer
|
| +** for any missing APIs.
|
| +*/
|
| +#ifndef SQLITE_ENABLE_COLUMN_METADATA
|
| +# define sqlite3_column_database_name 0
|
| +# define sqlite3_column_database_name16 0
|
| +# define sqlite3_column_table_name 0
|
| +# define sqlite3_column_table_name16 0
|
| +# define sqlite3_column_origin_name 0
|
| +# define sqlite3_column_origin_name16 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_AUTHORIZATION
|
| +# define sqlite3_set_authorizer 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_UTF16
|
| +# define sqlite3_bind_text16 0
|
| +# define sqlite3_collation_needed16 0
|
| +# define sqlite3_column_decltype16 0
|
| +# define sqlite3_column_name16 0
|
| +# define sqlite3_column_text16 0
|
| +# define sqlite3_complete16 0
|
| +# define sqlite3_create_collation16 0
|
| +# define sqlite3_create_function16 0
|
| +# define sqlite3_errmsg16 0
|
| +# define sqlite3_open16 0
|
| +# define sqlite3_prepare16 0
|
| +# define sqlite3_prepare16_v2 0
|
| +# define sqlite3_result_error16 0
|
| +# define sqlite3_result_text16 0
|
| +# define sqlite3_result_text16be 0
|
| +# define sqlite3_result_text16le 0
|
| +# define sqlite3_value_text16 0
|
| +# define sqlite3_value_text16be 0
|
| +# define sqlite3_value_text16le 0
|
| +# define sqlite3_column_database_name16 0
|
| +# define sqlite3_column_table_name16 0
|
| +# define sqlite3_column_origin_name16 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_COMPLETE
|
| +# define sqlite3_complete 0
|
| +# define sqlite3_complete16 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_DECLTYPE
|
| +# define sqlite3_column_decltype16 0
|
| +# define sqlite3_column_decltype 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
|
| +# define sqlite3_progress_handler 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_VIRTUALTABLE
|
| +# define sqlite3_create_module 0
|
| +# define sqlite3_create_module_v2 0
|
| +# define sqlite3_declare_vtab 0
|
| +# define sqlite3_vtab_config 0
|
| +# define sqlite3_vtab_on_conflict 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_SHARED_CACHE
|
| +# define sqlite3_enable_shared_cache 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_TRACE
|
| +# define sqlite3_profile 0
|
| +# define sqlite3_trace 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_GET_TABLE
|
| +# define sqlite3_free_table 0
|
| +# define sqlite3_get_table 0
|
| +#endif
|
| +
|
| +#ifdef SQLITE_OMIT_INCRBLOB
|
| +#define sqlite3_bind_zeroblob 0
|
| +#define sqlite3_blob_bytes 0
|
| +#define sqlite3_blob_close 0
|
| +#define sqlite3_blob_open 0
|
| +#define sqlite3_blob_read 0
|
| +#define sqlite3_blob_write 0
|
| +#define sqlite3_blob_reopen 0
|
| +#endif
|
| +
|
| +/*
|
| +** The following structure contains pointers to all SQLite API routines.
|
| +** A pointer to this structure is passed into extensions when they are
|
| +** loaded so that the extension can make calls back into the SQLite
|
| +** library.
|
| +**
|
| +** When adding new APIs, add them to the bottom of this structure
|
| +** in order to preserve backwards compatibility.
|
| +**
|
| +** Extensions that use newer APIs should first call the
|
| +** sqlite3_libversion_number() to make sure that the API they
|
| +** intend to use is supported by the library. Extensions should
|
| +** also check to make sure that the pointer to the function is
|
| +** not NULL before calling it.
|
| +*/
|
| +static const sqlite3_api_routines sqlite3Apis = {
|
| + sqlite3_aggregate_context,
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| + sqlite3_aggregate_count,
|
| +#else
|
| + 0,
|
| +#endif
|
| + sqlite3_bind_blob,
|
| + sqlite3_bind_double,
|
| + sqlite3_bind_int,
|
| + sqlite3_bind_int64,
|
| + sqlite3_bind_null,
|
| + sqlite3_bind_parameter_count,
|
| + sqlite3_bind_parameter_index,
|
| + sqlite3_bind_parameter_name,
|
| + sqlite3_bind_text,
|
| + sqlite3_bind_text16,
|
| + sqlite3_bind_value,
|
| + sqlite3_busy_handler,
|
| + sqlite3_busy_timeout,
|
| + sqlite3_changes,
|
| + sqlite3_close,
|
| + sqlite3_collation_needed,
|
| + sqlite3_collation_needed16,
|
| + sqlite3_column_blob,
|
| + sqlite3_column_bytes,
|
| + sqlite3_column_bytes16,
|
| + sqlite3_column_count,
|
| + sqlite3_column_database_name,
|
| + sqlite3_column_database_name16,
|
| + sqlite3_column_decltype,
|
| + sqlite3_column_decltype16,
|
| + sqlite3_column_double,
|
| + sqlite3_column_int,
|
| + sqlite3_column_int64,
|
| + sqlite3_column_name,
|
| + sqlite3_column_name16,
|
| + sqlite3_column_origin_name,
|
| + sqlite3_column_origin_name16,
|
| + sqlite3_column_table_name,
|
| + sqlite3_column_table_name16,
|
| + sqlite3_column_text,
|
| + sqlite3_column_text16,
|
| + sqlite3_column_type,
|
| + sqlite3_column_value,
|
| + sqlite3_commit_hook,
|
| + sqlite3_complete,
|
| + sqlite3_complete16,
|
| + sqlite3_create_collation,
|
| + sqlite3_create_collation16,
|
| + sqlite3_create_function,
|
| + sqlite3_create_function16,
|
| + sqlite3_create_module,
|
| + sqlite3_data_count,
|
| + sqlite3_db_handle,
|
| + sqlite3_declare_vtab,
|
| + sqlite3_enable_shared_cache,
|
| + sqlite3_errcode,
|
| + sqlite3_errmsg,
|
| + sqlite3_errmsg16,
|
| + sqlite3_exec,
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| + sqlite3_expired,
|
| +#else
|
| + 0,
|
| +#endif
|
| + sqlite3_finalize,
|
| + sqlite3_free,
|
| + sqlite3_free_table,
|
| + sqlite3_get_autocommit,
|
| + sqlite3_get_auxdata,
|
| + sqlite3_get_table,
|
| + 0, /* Was sqlite3_global_recover(), but that function is deprecated */
|
| + sqlite3_interrupt,
|
| + sqlite3_last_insert_rowid,
|
| + sqlite3_libversion,
|
| + sqlite3_libversion_number,
|
| + sqlite3_malloc,
|
| + sqlite3_mprintf,
|
| + sqlite3_open,
|
| + sqlite3_open16,
|
| + sqlite3_prepare,
|
| + sqlite3_prepare16,
|
| + sqlite3_profile,
|
| + sqlite3_progress_handler,
|
| + sqlite3_realloc,
|
| + sqlite3_reset,
|
| + sqlite3_result_blob,
|
| + sqlite3_result_double,
|
| + sqlite3_result_error,
|
| + sqlite3_result_error16,
|
| + sqlite3_result_int,
|
| + sqlite3_result_int64,
|
| + sqlite3_result_null,
|
| + sqlite3_result_text,
|
| + sqlite3_result_text16,
|
| + sqlite3_result_text16be,
|
| + sqlite3_result_text16le,
|
| + sqlite3_result_value,
|
| + sqlite3_rollback_hook,
|
| + sqlite3_set_authorizer,
|
| + sqlite3_set_auxdata,
|
| + sqlite3_snprintf,
|
| + sqlite3_step,
|
| + sqlite3_table_column_metadata,
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| + sqlite3_thread_cleanup,
|
| +#else
|
| + 0,
|
| +#endif
|
| + sqlite3_total_changes,
|
| + sqlite3_trace,
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| + sqlite3_transfer_bindings,
|
| +#else
|
| + 0,
|
| +#endif
|
| + sqlite3_update_hook,
|
| + sqlite3_user_data,
|
| + sqlite3_value_blob,
|
| + sqlite3_value_bytes,
|
| + sqlite3_value_bytes16,
|
| + sqlite3_value_double,
|
| + sqlite3_value_int,
|
| + sqlite3_value_int64,
|
| + sqlite3_value_numeric_type,
|
| + sqlite3_value_text,
|
| + sqlite3_value_text16,
|
| + sqlite3_value_text16be,
|
| + sqlite3_value_text16le,
|
| + sqlite3_value_type,
|
| + sqlite3_vmprintf,
|
| + /*
|
| + ** The original API set ends here. All extensions can call any
|
| + ** of the APIs above provided that the pointer is not NULL. But
|
| + ** before calling APIs that follow, extension should check the
|
| + ** sqlite3_libversion_number() to make sure they are dealing with
|
| + ** a library that is new enough to support that API.
|
| + *************************************************************************
|
| + */
|
| + sqlite3_overload_function,
|
| +
|
| + /*
|
| + ** Added after 3.3.13
|
| + */
|
| + sqlite3_prepare_v2,
|
| + sqlite3_prepare16_v2,
|
| + sqlite3_clear_bindings,
|
| +
|
| + /*
|
| + ** Added for 3.4.1
|
| + */
|
| + sqlite3_create_module_v2,
|
| +
|
| + /*
|
| + ** Added for 3.5.0
|
| + */
|
| + sqlite3_bind_zeroblob,
|
| + sqlite3_blob_bytes,
|
| + sqlite3_blob_close,
|
| + sqlite3_blob_open,
|
| + sqlite3_blob_read,
|
| + sqlite3_blob_write,
|
| + sqlite3_create_collation_v2,
|
| + sqlite3_file_control,
|
| + sqlite3_memory_highwater,
|
| + sqlite3_memory_used,
|
| +#ifdef SQLITE_MUTEX_OMIT
|
| + 0,
|
| + 0,
|
| + 0,
|
| + 0,
|
| + 0,
|
| +#else
|
| + sqlite3_mutex_alloc,
|
| + sqlite3_mutex_enter,
|
| + sqlite3_mutex_free,
|
| + sqlite3_mutex_leave,
|
| + sqlite3_mutex_try,
|
| +#endif
|
| + sqlite3_open_v2,
|
| + sqlite3_release_memory,
|
| + sqlite3_result_error_nomem,
|
| + sqlite3_result_error_toobig,
|
| + sqlite3_sleep,
|
| + sqlite3_soft_heap_limit,
|
| + sqlite3_vfs_find,
|
| + sqlite3_vfs_register,
|
| + sqlite3_vfs_unregister,
|
| +
|
| + /*
|
| + ** Added for 3.5.8
|
| + */
|
| + sqlite3_threadsafe,
|
| + sqlite3_result_zeroblob,
|
| + sqlite3_result_error_code,
|
| + sqlite3_test_control,
|
| + sqlite3_randomness,
|
| + sqlite3_context_db_handle,
|
| +
|
| + /*
|
| + ** Added for 3.6.0
|
| + */
|
| + sqlite3_extended_result_codes,
|
| + sqlite3_limit,
|
| + sqlite3_next_stmt,
|
| + sqlite3_sql,
|
| + sqlite3_status,
|
| +
|
| + /*
|
| + ** Added for 3.7.4
|
| + */
|
| + sqlite3_backup_finish,
|
| + sqlite3_backup_init,
|
| + sqlite3_backup_pagecount,
|
| + sqlite3_backup_remaining,
|
| + sqlite3_backup_step,
|
| +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
| + sqlite3_compileoption_get,
|
| + sqlite3_compileoption_used,
|
| +#else
|
| + 0,
|
| + 0,
|
| +#endif
|
| + sqlite3_create_function_v2,
|
| + sqlite3_db_config,
|
| + sqlite3_db_mutex,
|
| + sqlite3_db_status,
|
| + sqlite3_extended_errcode,
|
| + sqlite3_log,
|
| + sqlite3_soft_heap_limit64,
|
| + sqlite3_sourceid,
|
| + sqlite3_stmt_status,
|
| + sqlite3_strnicmp,
|
| +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
| + sqlite3_unlock_notify,
|
| +#else
|
| + 0,
|
| +#endif
|
| +#ifndef SQLITE_OMIT_WAL
|
| + sqlite3_wal_autocheckpoint,
|
| + sqlite3_wal_checkpoint,
|
| + sqlite3_wal_hook,
|
| +#else
|
| + 0,
|
| + 0,
|
| + 0,
|
| +#endif
|
| + sqlite3_blob_reopen,
|
| + sqlite3_vtab_config,
|
| + sqlite3_vtab_on_conflict,
|
| + sqlite3_close_v2,
|
| + sqlite3_db_filename,
|
| + sqlite3_db_readonly,
|
| + sqlite3_db_release_memory,
|
| + sqlite3_errstr,
|
| + sqlite3_stmt_busy,
|
| + sqlite3_stmt_readonly,
|
| + sqlite3_stricmp,
|
| + sqlite3_uri_boolean,
|
| + sqlite3_uri_int64,
|
| + sqlite3_uri_parameter,
|
| + sqlite3_vsnprintf,
|
| + sqlite3_wal_checkpoint_v2,
|
| + /* Version 3.8.7 and later */
|
| + sqlite3_auto_extension,
|
| + sqlite3_bind_blob64,
|
| + sqlite3_bind_text64,
|
| + sqlite3_cancel_auto_extension,
|
| + sqlite3_load_extension,
|
| + sqlite3_malloc64,
|
| + sqlite3_msize,
|
| + sqlite3_realloc64,
|
| + sqlite3_reset_auto_extension,
|
| + sqlite3_result_blob64,
|
| + sqlite3_result_text64,
|
| + sqlite3_strglob,
|
| + /* Version 3.8.11 and later */
|
| + (sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup,
|
| + sqlite3_value_free,
|
| + sqlite3_result_zeroblob64,
|
| + sqlite3_bind_zeroblob64,
|
| + /* Version 3.9.0 and later */
|
| + sqlite3_value_subtype,
|
| + sqlite3_result_subtype,
|
| + /* Version 3.10.0 and later */
|
| + sqlite3_status64,
|
| + sqlite3_strlike,
|
| + sqlite3_db_cacheflush
|
| +};
|
| +
|
| +/*
|
| +** Attempt to load an SQLite extension library contained in the file
|
| +** zFile. The entry point is zProc. zProc may be 0 in which case a
|
| +** default entry point name (sqlite3_extension_init) is used. Use
|
| +** of the default name is recommended.
|
| +**
|
| +** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
|
| +**
|
| +** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
|
| +** error message text. The calling function should free this memory
|
| +** by calling sqlite3DbFree(db, ).
|
| +*/
|
| +static int sqlite3LoadExtension(
|
| + sqlite3 *db, /* Load the extension into this database connection */
|
| + const char *zFile, /* Name of the shared library containing extension */
|
| + const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
|
| + char **pzErrMsg /* Put error message here if not 0 */
|
| +){
|
| + sqlite3_vfs *pVfs = db->pVfs;
|
| + void *handle;
|
| + int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
| + char *zErrmsg = 0;
|
| + const char *zEntry;
|
| + char *zAltEntry = 0;
|
| + void **aHandle;
|
| + u64 nMsg = 300 + sqlite3Strlen30(zFile);
|
| + int ii;
|
| +
|
| + /* Shared library endings to try if zFile cannot be loaded as written */
|
| + static const char *azEndings[] = {
|
| +#if SQLITE_OS_WIN
|
| + "dll"
|
| +#elif defined(__APPLE__)
|
| + "dylib"
|
| +#else
|
| + "so"
|
| +#endif
|
| + };
|
| +
|
| +
|
| + if( pzErrMsg ) *pzErrMsg = 0;
|
| +
|
| + /* Ticket #1863. To avoid a creating security problems for older
|
| + ** applications that relink against newer versions of SQLite, the
|
| + ** ability to run load_extension is turned off by default. One
|
| + ** must call sqlite3_enable_load_extension() to turn on extension
|
| + ** loading. Otherwise you get the following error.
|
| + */
|
| + if( (db->flags & SQLITE_LoadExtension)==0 ){
|
| + if( pzErrMsg ){
|
| + *pzErrMsg = sqlite3_mprintf("not authorized");
|
| + }
|
| + return SQLITE_ERROR;
|
| + }
|
| +
|
| + zEntry = zProc ? zProc : "sqlite3_extension_init";
|
| +
|
| + handle = sqlite3OsDlOpen(pVfs, zFile);
|
| +#if SQLITE_OS_UNIX || SQLITE_OS_WIN
|
| + for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
|
| + char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
|
| + if( zAltFile==0 ) return SQLITE_NOMEM;
|
| + handle = sqlite3OsDlOpen(pVfs, zAltFile);
|
| + sqlite3_free(zAltFile);
|
| + }
|
| +#endif
|
| + if( handle==0 ){
|
| + if( pzErrMsg ){
|
| + *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
|
| + if( zErrmsg ){
|
| + sqlite3_snprintf(nMsg, zErrmsg,
|
| + "unable to open shared library [%s]", zFile);
|
| + sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
|
| + }
|
| + }
|
| + return SQLITE_ERROR;
|
| + }
|
| + xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
|
| + sqlite3OsDlSym(pVfs, handle, zEntry);
|
| +
|
| + /* If no entry point was specified and the default legacy
|
| + ** entry point name "sqlite3_extension_init" was not found, then
|
| + ** construct an entry point name "sqlite3_X_init" where the X is
|
| + ** replaced by the lowercase value of every ASCII alphabetic
|
| + ** character in the filename after the last "/" upto the first ".",
|
| + ** and eliding the first three characters if they are "lib".
|
| + ** Examples:
|
| + **
|
| + ** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init
|
| + ** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init
|
| + */
|
| + if( xInit==0 && zProc==0 ){
|
| + int iFile, iEntry, c;
|
| + int ncFile = sqlite3Strlen30(zFile);
|
| + zAltEntry = sqlite3_malloc64(ncFile+30);
|
| + if( zAltEntry==0 ){
|
| + sqlite3OsDlClose(pVfs, handle);
|
| + return SQLITE_NOMEM;
|
| + }
|
| + memcpy(zAltEntry, "sqlite3_", 8);
|
| + for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
|
| + iFile++;
|
| + if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
|
| + for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
|
| + if( sqlite3Isalpha(c) ){
|
| + zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c];
|
| + }
|
| + }
|
| + memcpy(zAltEntry+iEntry, "_init", 6);
|
| + zEntry = zAltEntry;
|
| + xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
|
| + sqlite3OsDlSym(pVfs, handle, zEntry);
|
| + }
|
| + if( xInit==0 ){
|
| + if( pzErrMsg ){
|
| + nMsg += sqlite3Strlen30(zEntry);
|
| + *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
|
| + if( zErrmsg ){
|
| + sqlite3_snprintf(nMsg, zErrmsg,
|
| + "no entry point [%s] in shared library [%s]", zEntry, zFile);
|
| + sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
|
| + }
|
| + }
|
| + sqlite3OsDlClose(pVfs, handle);
|
| + sqlite3_free(zAltEntry);
|
| + return SQLITE_ERROR;
|
| + }
|
| + sqlite3_free(zAltEntry);
|
| + if( xInit(db, &zErrmsg, &sqlite3Apis) ){
|
| + if( pzErrMsg ){
|
| + *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
|
| + }
|
| + sqlite3_free(zErrmsg);
|
| + sqlite3OsDlClose(pVfs, handle);
|
| + return SQLITE_ERROR;
|
| + }
|
| +
|
| + /* Append the new shared library handle to the db->aExtension array. */
|
| + aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
|
| + if( aHandle==0 ){
|
| + return SQLITE_NOMEM;
|
| + }
|
| + if( db->nExtension>0 ){
|
| + memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
|
| + }
|
| + sqlite3DbFree(db, db->aExtension);
|
| + db->aExtension = aHandle;
|
| +
|
| + db->aExtension[db->nExtension++] = handle;
|
| + return SQLITE_OK;
|
| +}
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
|
| + sqlite3 *db, /* Load the extension into this database connection */
|
| + const char *zFile, /* Name of the shared library containing extension */
|
| + const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
|
| + char **pzErrMsg /* Put error message here if not 0 */
|
| +){
|
| + int rc;
|
| + sqlite3_mutex_enter(db->mutex);
|
| + rc = sqlite3LoadExtension(db, zFile, zProc, pzErrMsg);
|
| + rc = sqlite3ApiExit(db, rc);
|
| + sqlite3_mutex_leave(db->mutex);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Call this routine when the database connection is closing in order
|
| +** to clean up loaded extensions
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){
|
| + int i;
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + for(i=0; i<db->nExtension; i++){
|
| + sqlite3OsDlClose(db->pVfs, db->aExtension[i]);
|
| + }
|
| + sqlite3DbFree(db, db->aExtension);
|
| +}
|
| +
|
| +/*
|
| +** Enable or disable extension loading. Extension loading is disabled by
|
| +** default so as not to open security holes in older applications.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff){
|
| + sqlite3_mutex_enter(db->mutex);
|
| + if( onoff ){
|
| + db->flags |= SQLITE_LoadExtension;
|
| + }else{
|
| + db->flags &= ~SQLITE_LoadExtension;
|
| + }
|
| + sqlite3_mutex_leave(db->mutex);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
| +
|
| +/*
|
| +** The auto-extension code added regardless of whether or not extension
|
| +** loading is supported. We need a dummy sqlite3Apis pointer for that
|
| +** code if regular extension loading is not available. This is that
|
| +** dummy pointer.
|
| +*/
|
| +#ifdef SQLITE_OMIT_LOAD_EXTENSION
|
| +static const sqlite3_api_routines sqlite3Apis = { 0 };
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** The following object holds the list of automatically loaded
|
| +** extensions.
|
| +**
|
| +** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER
|
| +** mutex must be held while accessing this list.
|
| +*/
|
| +typedef struct sqlite3AutoExtList sqlite3AutoExtList;
|
| +static SQLITE_WSD struct sqlite3AutoExtList {
|
| + u32 nExt; /* Number of entries in aExt[] */
|
| + void (**aExt)(void); /* Pointers to the extension init functions */
|
| +} sqlite3Autoext = { 0, 0 };
|
| +
|
| +/* The "wsdAutoext" macro will resolve to the autoextension
|
| +** state vector. If writable static data is unsupported on the target,
|
| +** we have to locate the state vector at run-time. In the more common
|
| +** case where writable static data is supported, wsdStat can refer directly
|
| +** to the "sqlite3Autoext" state vector declared above.
|
| +*/
|
| +#ifdef SQLITE_OMIT_WSD
|
| +# define wsdAutoextInit \
|
| + sqlite3AutoExtList *x = &GLOBAL(sqlite3AutoExtList,sqlite3Autoext)
|
| +# define wsdAutoext x[0]
|
| +#else
|
| +# define wsdAutoextInit
|
| +# define wsdAutoext sqlite3Autoext
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** Register a statically linked extension that is automatically
|
| +** loaded by every new database connection.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
|
| + int rc = SQLITE_OK;
|
| +#ifndef SQLITE_OMIT_AUTOINIT
|
| + rc = sqlite3_initialize();
|
| + if( rc ){
|
| + return rc;
|
| + }else
|
| +#endif
|
| + {
|
| + u32 i;
|
| +#if SQLITE_THREADSAFE
|
| + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
| +#endif
|
| + wsdAutoextInit;
|
| + sqlite3_mutex_enter(mutex);
|
| + for(i=0; i<wsdAutoext.nExt; i++){
|
| + if( wsdAutoext.aExt[i]==xInit ) break;
|
| + }
|
| + if( i==wsdAutoext.nExt ){
|
| + u64 nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
|
| + void (**aNew)(void);
|
| + aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
|
| + if( aNew==0 ){
|
| + rc = SQLITE_NOMEM;
|
| + }else{
|
| + wsdAutoext.aExt = aNew;
|
| + wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
|
| + wsdAutoext.nExt++;
|
| + }
|
| + }
|
| + sqlite3_mutex_leave(mutex);
|
| + assert( (rc&0xff)==rc );
|
| + return rc;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Cancel a prior call to sqlite3_auto_extension. Remove xInit from the
|
| +** set of routines that is invoked for each new database connection, if it
|
| +** is currently on the list. If xInit is not on the list, then this
|
| +** routine is a no-op.
|
| +**
|
| +** Return 1 if xInit was found on the list and removed. Return 0 if xInit
|
| +** was not on the list.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)){
|
| +#if SQLITE_THREADSAFE
|
| + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
| +#endif
|
| + int i;
|
| + int n = 0;
|
| + wsdAutoextInit;
|
| + sqlite3_mutex_enter(mutex);
|
| + for(i=(int)wsdAutoext.nExt-1; i>=0; i--){
|
| + if( wsdAutoext.aExt[i]==xInit ){
|
| + wsdAutoext.nExt--;
|
| + wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt];
|
| + n++;
|
| + break;
|
| + }
|
| + }
|
| + sqlite3_mutex_leave(mutex);
|
| + return n;
|
| +}
|
| +
|
| +/*
|
| +** Reset the automatic extension loading mechanism.
|
| +*/
|
| +SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void){
|
| +#ifndef SQLITE_OMIT_AUTOINIT
|
| + if( sqlite3_initialize()==SQLITE_OK )
|
| +#endif
|
| + {
|
| +#if SQLITE_THREADSAFE
|
| + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
| +#endif
|
| + wsdAutoextInit;
|
| + sqlite3_mutex_enter(mutex);
|
| + sqlite3_free(wsdAutoext.aExt);
|
| + wsdAutoext.aExt = 0;
|
| + wsdAutoext.nExt = 0;
|
| + sqlite3_mutex_leave(mutex);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Load all automatic extensions.
|
| +**
|
| +** If anything goes wrong, set an error in the database connection.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
|
| + u32 i;
|
| + int go = 1;
|
| + int rc;
|
| + int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
| +
|
| + wsdAutoextInit;
|
| + if( wsdAutoext.nExt==0 ){
|
| + /* Common case: early out without every having to acquire a mutex */
|
| + return;
|
| + }
|
| + for(i=0; go; i++){
|
| + char *zErrmsg;
|
| +#if SQLITE_THREADSAFE
|
| + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
| +#endif
|
| + sqlite3_mutex_enter(mutex);
|
| + if( i>=wsdAutoext.nExt ){
|
| + xInit = 0;
|
| + go = 0;
|
| + }else{
|
| + xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
|
| + wsdAutoext.aExt[i];
|
| + }
|
| + sqlite3_mutex_leave(mutex);
|
| + zErrmsg = 0;
|
| + if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
|
| + sqlite3ErrorWithMsg(db, rc,
|
| + "automatic extension loading failed: %s", zErrmsg);
|
| + go = 0;
|
| + }
|
| + sqlite3_free(zErrmsg);
|
| + }
|
| +}
|
| +
|
| +/************** End of loadext.c *********************************************/
|
| +/************** Begin file pragma.c ******************************************/
|
| +/*
|
| +** 2003 April 6
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains code used to implement the PRAGMA command.
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
|
| +# if defined(__APPLE__)
|
| +# define SQLITE_ENABLE_LOCKING_STYLE 1
|
| +# else
|
| +# define SQLITE_ENABLE_LOCKING_STYLE 0
|
| +# endif
|
| +#endif
|
| +
|
| +/***************************************************************************
|
| +** The "pragma.h" include file is an automatically generated file that
|
| +** that includes the PragType_XXXX macro definitions and the aPragmaName[]
|
| +** object. This ensures that the aPragmaName[] table is arranged in
|
| +** lexicographical order to facility a binary search of the pragma name.
|
| +** Do not edit pragma.h directly. Edit and rerun the script in at
|
| +** ../tool/mkpragmatab.tcl. */
|
| +/************** Include pragma.h in the middle of pragma.c *******************/
|
| +/************** Begin file pragma.h ******************************************/
|
| +/* DO NOT EDIT!
|
| +** This file is automatically generated by the script at
|
| +** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit
|
| +** that script and rerun it.
|
| +*/
|
| +#define PragTyp_HEADER_VALUE 0
|
| +#define PragTyp_AUTO_VACUUM 1
|
| +#define PragTyp_FLAG 2
|
| +#define PragTyp_BUSY_TIMEOUT 3
|
| +#define PragTyp_CACHE_SIZE 4
|
| +#define PragTyp_CACHE_SPILL 5
|
| +#define PragTyp_CASE_SENSITIVE_LIKE 6
|
| +#define PragTyp_COLLATION_LIST 7
|
| +#define PragTyp_COMPILE_OPTIONS 8
|
| +#define PragTyp_DATA_STORE_DIRECTORY 9
|
| +#define PragTyp_DATABASE_LIST 10
|
| +#define PragTyp_DEFAULT_CACHE_SIZE 11
|
| +#define PragTyp_ENCODING 12
|
| +#define PragTyp_FOREIGN_KEY_CHECK 13
|
| +#define PragTyp_FOREIGN_KEY_LIST 14
|
| +#define PragTyp_INCREMENTAL_VACUUM 15
|
| +#define PragTyp_INDEX_INFO 16
|
| +#define PragTyp_INDEX_LIST 17
|
| +#define PragTyp_INTEGRITY_CHECK 18
|
| +#define PragTyp_JOURNAL_MODE 19
|
| +#define PragTyp_JOURNAL_SIZE_LIMIT 20
|
| +#define PragTyp_LOCK_PROXY_FILE 21
|
| +#define PragTyp_LOCKING_MODE 22
|
| +#define PragTyp_PAGE_COUNT 23
|
| +#define PragTyp_MMAP_SIZE 24
|
| +#define PragTyp_PAGE_SIZE 25
|
| +#define PragTyp_SECURE_DELETE 26
|
| +#define PragTyp_SHRINK_MEMORY 27
|
| +#define PragTyp_SOFT_HEAP_LIMIT 28
|
| +#define PragTyp_STATS 29
|
| +#define PragTyp_SYNCHRONOUS 30
|
| +#define PragTyp_TABLE_INFO 31
|
| +#define PragTyp_TEMP_STORE 32
|
| +#define PragTyp_TEMP_STORE_DIRECTORY 33
|
| +#define PragTyp_THREADS 34
|
| +#define PragTyp_WAL_AUTOCHECKPOINT 35
|
| +#define PragTyp_WAL_CHECKPOINT 36
|
| +#define PragTyp_ACTIVATE_EXTENSIONS 37
|
| +#define PragTyp_HEXKEY 38
|
| +#define PragTyp_KEY 39
|
| +#define PragTyp_REKEY 40
|
| +#define PragTyp_LOCK_STATUS 41
|
| +#define PragTyp_PARSER_TRACE 42
|
| +#define PragFlag_NeedSchema 0x01
|
| +#define PragFlag_ReadOnly 0x02
|
| +static const struct sPragmaNames {
|
| + const char *const zName; /* Name of pragma */
|
| + u8 ePragTyp; /* PragTyp_XXX value */
|
| + u8 mPragFlag; /* Zero or more PragFlag_XXX values */
|
| + u32 iArg; /* Extra argument */
|
| +} aPragmaNames[] = {
|
| +#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
|
| + { /* zName: */ "activate_extensions",
|
| + /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
| + { /* zName: */ "application_id",
|
| + /* ePragTyp: */ PragTyp_HEADER_VALUE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ BTREE_APPLICATION_ID },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_AUTOVACUUM)
|
| + { /* zName: */ "auto_vacuum",
|
| + /* ePragTyp: */ PragTyp_AUTO_VACUUM,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| +#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
|
| + { /* zName: */ "automatic_index",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_AutoIndex },
|
| +#endif
|
| +#endif
|
| + { /* zName: */ "busy_timeout",
|
| + /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
| + { /* zName: */ "cache_size",
|
| + /* ePragTyp: */ PragTyp_CACHE_SIZE,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "cache_spill",
|
| + /* ePragTyp: */ PragTyp_CACHE_SPILL,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| + { /* zName: */ "case_sensitive_like",
|
| + /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "cell_size_check",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_CellSizeCk },
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "checkpoint_fullfsync",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_CkptFullFSync },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
| + { /* zName: */ "collation_list",
|
| + /* ePragTyp: */ PragTyp_COLLATION_LIST,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
|
| + { /* zName: */ "compile_options",
|
| + /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "count_changes",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_CountRows },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
|
| + { /* zName: */ "data_store_directory",
|
| + /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
| + { /* zName: */ "data_version",
|
| + /* ePragTyp: */ PragTyp_HEADER_VALUE,
|
| + /* ePragFlag: */ PragFlag_ReadOnly,
|
| + /* iArg: */ BTREE_DATA_VERSION },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
| + { /* zName: */ "database_list",
|
| + /* ePragTyp: */ PragTyp_DATABASE_LIST,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
| + { /* zName: */ "default_cache_size",
|
| + /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
| + { /* zName: */ "defer_foreign_keys",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_DeferFKs },
|
| +#endif
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "empty_result_callbacks",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_NullCallback },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_UTF16)
|
| + { /* zName: */ "encoding",
|
| + /* ePragTyp: */ PragTyp_ENCODING,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
| + { /* zName: */ "foreign_key_check",
|
| + /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FOREIGN_KEY)
|
| + { /* zName: */ "foreign_key_list",
|
| + /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
| + { /* zName: */ "foreign_keys",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_ForeignKeys },
|
| +#endif
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
| + { /* zName: */ "freelist_count",
|
| + /* ePragTyp: */ PragTyp_HEADER_VALUE,
|
| + /* ePragFlag: */ PragFlag_ReadOnly,
|
| + /* iArg: */ BTREE_FREE_PAGE_COUNT },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "full_column_names",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_FullColNames },
|
| + { /* zName: */ "fullfsync",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_FullFSync },
|
| +#endif
|
| +#if defined(SQLITE_HAS_CODEC)
|
| + { /* zName: */ "hexkey",
|
| + /* ePragTyp: */ PragTyp_HEXKEY,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "hexrekey",
|
| + /* ePragTyp: */ PragTyp_HEXKEY,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| +#if !defined(SQLITE_OMIT_CHECK)
|
| + { /* zName: */ "ignore_check_constraints",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_IgnoreChecks },
|
| +#endif
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_AUTOVACUUM)
|
| + { /* zName: */ "incremental_vacuum",
|
| + /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
| + { /* zName: */ "index_info",
|
| + /* ePragTyp: */ PragTyp_INDEX_INFO,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "index_list",
|
| + /* ePragTyp: */ PragTyp_INDEX_LIST,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "index_xinfo",
|
| + /* ePragTyp: */ PragTyp_INDEX_INFO,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 1 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
|
| + { /* zName: */ "integrity_check",
|
| + /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
| + { /* zName: */ "journal_mode",
|
| + /* ePragTyp: */ PragTyp_JOURNAL_MODE,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "journal_size_limit",
|
| + /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if defined(SQLITE_HAS_CODEC)
|
| + { /* zName: */ "key",
|
| + /* ePragTyp: */ PragTyp_KEY,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "legacy_file_format",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_LegacyFileFmt },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
|
| + { /* zName: */ "lock_proxy_file",
|
| + /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
| + { /* zName: */ "lock_status",
|
| + /* ePragTyp: */ PragTyp_LOCK_STATUS,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
| + { /* zName: */ "locking_mode",
|
| + /* ePragTyp: */ PragTyp_LOCKING_MODE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "max_page_count",
|
| + /* ePragTyp: */ PragTyp_PAGE_COUNT,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "mmap_size",
|
| + /* ePragTyp: */ PragTyp_MMAP_SIZE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "page_count",
|
| + /* ePragTyp: */ PragTyp_PAGE_COUNT,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "page_size",
|
| + /* ePragTyp: */ PragTyp_PAGE_SIZE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE)
|
| + { /* zName: */ "parser_trace",
|
| + /* ePragTyp: */ PragTyp_PARSER_TRACE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "query_only",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_QueryOnly },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
|
| + { /* zName: */ "quick_check",
|
| + /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "read_uncommitted",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_ReadUncommitted },
|
| + { /* zName: */ "recursive_triggers",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_RecTriggers },
|
| +#endif
|
| +#if defined(SQLITE_HAS_CODEC)
|
| + { /* zName: */ "rekey",
|
| + /* ePragTyp: */ PragTyp_REKEY,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "reverse_unordered_selects",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_ReverseOrder },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
| + { /* zName: */ "schema_version",
|
| + /* ePragTyp: */ PragTyp_HEADER_VALUE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ BTREE_SCHEMA_VERSION },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
| + { /* zName: */ "secure_delete",
|
| + /* ePragTyp: */ PragTyp_SECURE_DELETE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "short_column_names",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_ShortColNames },
|
| +#endif
|
| + { /* zName: */ "shrink_memory",
|
| + /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "soft_heap_limit",
|
| + /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| +#if defined(SQLITE_DEBUG)
|
| + { /* zName: */ "sql_trace",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_SqlTrace },
|
| +#endif
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
| + { /* zName: */ "stats",
|
| + /* ePragTyp: */ PragTyp_STATS,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
| + { /* zName: */ "synchronous",
|
| + /* ePragTyp: */ PragTyp_SYNCHRONOUS,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
| + { /* zName: */ "table_info",
|
| + /* ePragTyp: */ PragTyp_TABLE_INFO,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
| + { /* zName: */ "temp_store",
|
| + /* ePragTyp: */ PragTyp_TEMP_STORE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "temp_store_directory",
|
| + /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| + { /* zName: */ "threads",
|
| + /* ePragTyp: */ PragTyp_THREADS,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
| + { /* zName: */ "user_version",
|
| + /* ePragTyp: */ PragTyp_HEADER_VALUE,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ BTREE_USER_VERSION },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| +#if defined(SQLITE_DEBUG)
|
| + { /* zName: */ "vdbe_addoptrace",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_VdbeAddopTrace },
|
| + { /* zName: */ "vdbe_debug",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
|
| + { /* zName: */ "vdbe_eqp",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_VdbeEQP },
|
| + { /* zName: */ "vdbe_listing",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_VdbeListing },
|
| + { /* zName: */ "vdbe_trace",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_VdbeTrace },
|
| +#endif
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_WAL)
|
| + { /* zName: */ "wal_autocheckpoint",
|
| + /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ 0 },
|
| + { /* zName: */ "wal_checkpoint",
|
| + /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
|
| + /* ePragFlag: */ PragFlag_NeedSchema,
|
| + /* iArg: */ 0 },
|
| +#endif
|
| +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
| + { /* zName: */ "writable_schema",
|
| + /* ePragTyp: */ PragTyp_FLAG,
|
| + /* ePragFlag: */ 0,
|
| + /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
|
| +#endif
|
| +};
|
| +/* Number of pragmas: 60 on by default, 73 total. */
|
| +
|
| +/************** End of pragma.h **********************************************/
|
| +/************** Continuing where we left off in pragma.c *********************/
|
| +
|
| +/*
|
| +** Interpret the given string as a safety level. Return 0 for OFF,
|
| +** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
|
| +** unrecognized string argument. The FULL option is disallowed
|
| +** if the omitFull parameter it 1.
|
| +**
|
| +** Note that the values returned are one less that the values that
|
| +** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
|
| +** to support legacy SQL code. The safety level used to be boolean
|
| +** and older scripts may have used numbers 0 for OFF and 1 for ON.
|
| +*/
|
| +static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){
|
| + /* 123456789 123456789 */
|
| + static const char zText[] = "onoffalseyestruefull";
|
| + static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
|
| + static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
|
| + static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2};
|
| + int i, n;
|
| + if( sqlite3Isdigit(*z) ){
|
| + return (u8)sqlite3Atoi(z);
|
| + }
|
| + n = sqlite3Strlen30(z);
|
| + for(i=0; i<ArraySize(iLength)-omitFull; i++){
|
| + if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
|
| + return iValue[i];
|
| + }
|
| + }
|
| + return dflt;
|
| +}
|
| +
|
| +/*
|
| +** Interpret the given string as a boolean value.
|
| +*/
|
| +SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, u8 dflt){
|
| + return getSafetyLevel(z,1,dflt)!=0;
|
| +}
|
| +
|
| +/* The sqlite3GetBoolean() function is used by other modules but the
|
| +** remainder of this file is specific to PRAGMA processing. So omit
|
| +** the rest of the file if PRAGMAs are omitted from the build.
|
| +*/
|
| +#if !defined(SQLITE_OMIT_PRAGMA)
|
| +
|
| +/*
|
| +** Interpret the given string as a locking mode value.
|
| +*/
|
| +static int getLockingMode(const char *z){
|
| + if( z ){
|
| + if( 0==sqlite3StrICmp(z, "exclusive") ) return PAGER_LOCKINGMODE_EXCLUSIVE;
|
| + if( 0==sqlite3StrICmp(z, "normal") ) return PAGER_LOCKINGMODE_NORMAL;
|
| + }
|
| + return PAGER_LOCKINGMODE_QUERY;
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_AUTOVACUUM
|
| +/*
|
| +** Interpret the given string as an auto-vacuum mode value.
|
| +**
|
| +** The following strings, "none", "full" and "incremental" are
|
| +** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
|
| +*/
|
| +static int getAutoVacuum(const char *z){
|
| + int i;
|
| + if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
|
| + if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
|
| + if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
|
| + i = sqlite3Atoi(z);
|
| + return (u8)((i>=0&&i<=2)?i:0);
|
| +}
|
| +#endif /* ifndef SQLITE_OMIT_AUTOVACUUM */
|
| +
|
| +#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
| +/*
|
| +** Interpret the given string as a temp db location. Return 1 for file
|
| +** backed temporary databases, 2 for the Red-Black tree in memory database
|
| +** and 0 to use the compile-time default.
|
| +*/
|
| +static int getTempStore(const char *z){
|
| + if( z[0]>='0' && z[0]<='2' ){
|
| + return z[0] - '0';
|
| + }else if( sqlite3StrICmp(z, "file")==0 ){
|
| + return 1;
|
| + }else if( sqlite3StrICmp(z, "memory")==0 ){
|
| + return 2;
|
| + }else{
|
| + return 0;
|
| + }
|
| +}
|
| +#endif /* SQLITE_PAGER_PRAGMAS */
|
| +
|
| +#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
| +/*
|
| +** Invalidate temp storage, either when the temp storage is changed
|
| +** from default, or when 'file' and the temp_store_directory has changed
|
| +*/
|
| +static int invalidateTempStorage(Parse *pParse){
|
| + sqlite3 *db = pParse->db;
|
| + if( db->aDb[1].pBt!=0 ){
|
| + if( !db->autoCommit || sqlite3BtreeIsInReadTrans(db->aDb[1].pBt) ){
|
| + sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
|
| + "from within a transaction");
|
| + return SQLITE_ERROR;
|
| + }
|
| + sqlite3BtreeClose(db->aDb[1].pBt);
|
| + db->aDb[1].pBt = 0;
|
| + sqlite3ResetAllSchemasOfConnection(db);
|
| + }
|
| + return SQLITE_OK;
|
| +}
|
| +#endif /* SQLITE_PAGER_PRAGMAS */
|
| +
|
| +#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
| +/*
|
| +** If the TEMP database is open, close it and mark the database schema
|
| +** as needing reloading. This must be done when using the SQLITE_TEMP_STORE
|
| +** or DEFAULT_TEMP_STORE pragmas.
|
| +*/
|
| +static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
| + int ts = getTempStore(zStorageType);
|
| + sqlite3 *db = pParse->db;
|
| + if( db->temp_store==ts ) return SQLITE_OK;
|
| + if( invalidateTempStorage( pParse ) != SQLITE_OK ){
|
| + return SQLITE_ERROR;
|
| + }
|
| + db->temp_store = (u8)ts;
|
| + return SQLITE_OK;
|
| +}
|
| +#endif /* SQLITE_PAGER_PRAGMAS */
|
| +
|
| +/*
|
| +** Set the names of the first N columns to the values in azCol[]
|
| +*/
|
| +static void setAllColumnNames(
|
| + Vdbe *v, /* The query under construction */
|
| + int N, /* Number of columns */
|
| + const char **azCol /* Names of columns */
|
| +){
|
| + int i;
|
| + sqlite3VdbeSetNumCols(v, N);
|
| + for(i=0; i<N; i++){
|
| + sqlite3VdbeSetColName(v, i, COLNAME_NAME, azCol[i], SQLITE_STATIC);
|
| + }
|
| +}
|
| +static void setOneColumnName(Vdbe *v, const char *z){
|
| + setAllColumnNames(v, 1, &z);
|
| +}
|
| +
|
| +/*
|
| +** Generate code to return a single integer value.
|
| +*/
|
| +static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
|
| + sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8*)&value, P4_INT64);
|
| + setOneColumnName(v, zLabel);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
| +}
|
| +
|
| +/*
|
| +** Generate code to return a single text value.
|
| +*/
|
| +static void returnSingleText(
|
| + Vdbe *v, /* Prepared statement under construction */
|
| + const char *zLabel, /* Name of the result column */
|
| + const char *zValue /* Value to be returned */
|
| +){
|
| + if( zValue ){
|
| + sqlite3VdbeLoadString(v, 1, (const char*)zValue);
|
| + setOneColumnName(v, zLabel);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
| + }
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Set the safety_level and pager flags for pager iDb. Or if iDb<0
|
| +** set these values for all pagers.
|
| +*/
|
| +#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
| +static void setAllPagerFlags(sqlite3 *db){
|
| + if( db->autoCommit ){
|
| + Db *pDb = db->aDb;
|
| + int n = db->nDb;
|
| + assert( SQLITE_FullFSync==PAGER_FULLFSYNC );
|
| + assert( SQLITE_CkptFullFSync==PAGER_CKPT_FULLFSYNC );
|
| + assert( SQLITE_CacheSpill==PAGER_CACHESPILL );
|
| + assert( (PAGER_FULLFSYNC | PAGER_CKPT_FULLFSYNC | PAGER_CACHESPILL)
|
| + == PAGER_FLAGS_MASK );
|
| + assert( (pDb->safety_level & PAGER_SYNCHRONOUS_MASK)==pDb->safety_level );
|
| + while( (n--) > 0 ){
|
| + if( pDb->pBt ){
|
| + sqlite3BtreeSetPagerFlags(pDb->pBt,
|
| + pDb->safety_level | (db->flags & PAGER_FLAGS_MASK) );
|
| + }
|
| + pDb++;
|
| + }
|
| + }
|
| +}
|
| +#else
|
| +# define setAllPagerFlags(X) /* no-op */
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** Return a human-readable name for a constraint resolution action.
|
| +*/
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| +static const char *actionName(u8 action){
|
| + const char *zName;
|
| + switch( action ){
|
| + case OE_SetNull: zName = "SET NULL"; break;
|
| + case OE_SetDflt: zName = "SET DEFAULT"; break;
|
| + case OE_Cascade: zName = "CASCADE"; break;
|
| + case OE_Restrict: zName = "RESTRICT"; break;
|
| + default: zName = "NO ACTION";
|
| + assert( action==OE_None ); break;
|
| + }
|
| + return zName;
|
| +}
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
|
| +** defined in pager.h. This function returns the associated lowercase
|
| +** journal-mode name.
|
| +*/
|
| +SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
|
| + static char * const azModeName[] = {
|
| + "delete", "persist", "off", "truncate", "memory"
|
| +#ifndef SQLITE_OMIT_WAL
|
| + , "wal"
|
| +#endif
|
| + };
|
| + assert( PAGER_JOURNALMODE_DELETE==0 );
|
| + assert( PAGER_JOURNALMODE_PERSIST==1 );
|
| + assert( PAGER_JOURNALMODE_OFF==2 );
|
| + assert( PAGER_JOURNALMODE_TRUNCATE==3 );
|
| + assert( PAGER_JOURNALMODE_MEMORY==4 );
|
| + assert( PAGER_JOURNALMODE_WAL==5 );
|
| + assert( eMode>=0 && eMode<=ArraySize(azModeName) );
|
| +
|
| + if( eMode==ArraySize(azModeName) ) return 0;
|
| + return azModeName[eMode];
|
| +}
|
| +
|
| +/*
|
| +** Process a pragma statement.
|
| +**
|
| +** Pragmas are of this form:
|
| +**
|
| +** PRAGMA [schema.]id [= value]
|
| +**
|
| +** The identifier might also be a string. The value is a string, and
|
| +** identifier, or a number. If minusFlag is true, then the value is
|
| +** a number that was preceded by a minus sign.
|
| +**
|
| +** If the left side is "database.id" then pId1 is the database name
|
| +** and pId2 is the id. If the left side is just "id" then pId1 is the
|
| +** id and pId2 is any empty string.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3Pragma(
|
| + Parse *pParse,
|
| + Token *pId1, /* First part of [schema.]id field */
|
| + Token *pId2, /* Second part of [schema.]id field, or NULL */
|
| + Token *pValue, /* Token for <value>, or NULL */
|
| + int minusFlag /* True if a '-' sign preceded <value> */
|
| +){
|
| + char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */
|
| + char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
|
| + const char *zDb = 0; /* The database name */
|
| + Token *pId; /* Pointer to <id> token */
|
| + char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
|
| + int iDb; /* Database index for <database> */
|
| + int lwr, upr, mid = 0; /* Binary search bounds */
|
| + int rc; /* return value form SQLITE_FCNTL_PRAGMA */
|
| + sqlite3 *db = pParse->db; /* The database connection */
|
| + Db *pDb; /* The specific database being pragmaed */
|
| + Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
|
| + const struct sPragmaNames *pPragma;
|
| +
|
| + if( v==0 ) return;
|
| + sqlite3VdbeRunOnlyOnce(v);
|
| + pParse->nMem = 2;
|
| +
|
| + /* Interpret the [schema.] part of the pragma statement. iDb is the
|
| + ** index of the database this pragma is being applied to in db.aDb[]. */
|
| + iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
|
| + if( iDb<0 ) return;
|
| + pDb = &db->aDb[iDb];
|
| +
|
| + /* If the temp database has been explicitly named as part of the
|
| + ** pragma, make sure it is open.
|
| + */
|
| + if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){
|
| + return;
|
| + }
|
| +
|
| + zLeft = sqlite3NameFromToken(db, pId);
|
| + if( !zLeft ) return;
|
| + if( minusFlag ){
|
| + zRight = sqlite3MPrintf(db, "-%T", pValue);
|
| + }else{
|
| + zRight = sqlite3NameFromToken(db, pValue);
|
| + }
|
| +
|
| + assert( pId2 );
|
| + zDb = pId2->n>0 ? pDb->zName : 0;
|
| + if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
|
| + goto pragma_out;
|
| + }
|
| +
|
| + /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS
|
| + ** connection. If it returns SQLITE_OK, then assume that the VFS
|
| + ** handled the pragma and generate a no-op prepared statement.
|
| + **
|
| + ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed,
|
| + ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file
|
| + ** object corresponding to the database file to which the pragma
|
| + ** statement refers.
|
| + **
|
| + ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA
|
| + ** file control is an array of pointers to strings (char**) in which the
|
| + ** second element of the array is the name of the pragma and the third
|
| + ** element is the argument to the pragma or NULL if the pragma has no
|
| + ** argument.
|
| + */
|
| + aFcntl[0] = 0;
|
| + aFcntl[1] = zLeft;
|
| + aFcntl[2] = zRight;
|
| + aFcntl[3] = 0;
|
| + db->busyHandler.nBusy = 0;
|
| + rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
|
| + if( rc==SQLITE_OK ){
|
| + returnSingleText(v, "result", aFcntl[0]);
|
| + sqlite3_free(aFcntl[0]);
|
| + goto pragma_out;
|
| + }
|
| + if( rc!=SQLITE_NOTFOUND ){
|
| + if( aFcntl[0] ){
|
| + sqlite3ErrorMsg(pParse, "%s", aFcntl[0]);
|
| + sqlite3_free(aFcntl[0]);
|
| + }
|
| + pParse->nErr++;
|
| + pParse->rc = rc;
|
| + goto pragma_out;
|
| + }
|
| +
|
| + /* Locate the pragma in the lookup table */
|
| + lwr = 0;
|
| + upr = ArraySize(aPragmaNames)-1;
|
| + while( lwr<=upr ){
|
| + mid = (lwr+upr)/2;
|
| + rc = sqlite3_stricmp(zLeft, aPragmaNames[mid].zName);
|
| + if( rc==0 ) break;
|
| + if( rc<0 ){
|
| + upr = mid - 1;
|
| + }else{
|
| + lwr = mid + 1;
|
| + }
|
| + }
|
| + if( lwr>upr ) goto pragma_out;
|
| + pPragma = &aPragmaNames[mid];
|
| +
|
| + /* Make sure the database schema is loaded if the pragma requires that */
|
| + if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
|
| + if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
| + }
|
| +
|
| + /* Jump to the appropriate pragma handler */
|
| + switch( pPragma->ePragTyp ){
|
| +
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
| + /*
|
| + ** PRAGMA [schema.]default_cache_size
|
| + ** PRAGMA [schema.]default_cache_size=N
|
| + **
|
| + ** The first form reports the current persistent setting for the
|
| + ** page cache size. The value returned is the maximum number of
|
| + ** pages in the page cache. The second form sets both the current
|
| + ** page cache size value and the persistent page cache size value
|
| + ** stored in the database file.
|
| + **
|
| + ** Older versions of SQLite would set the default cache size to a
|
| + ** negative number to indicate synchronous=OFF. These days, synchronous
|
| + ** is always on by default regardless of the sign of the default cache
|
| + ** size. But continue to take the absolute value of the default cache
|
| + ** size of historical compatibility.
|
| + */
|
| + case PragTyp_DEFAULT_CACHE_SIZE: {
|
| + static const int iLn = VDBE_OFFSET_LINENO(2);
|
| + static const VdbeOpList getCacheSize[] = {
|
| + { OP_Transaction, 0, 0, 0}, /* 0 */
|
| + { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */
|
| + { OP_IfPos, 1, 8, 0},
|
| + { OP_Integer, 0, 2, 0},
|
| + { OP_Subtract, 1, 2, 1},
|
| + { OP_IfPos, 1, 8, 0},
|
| + { OP_Integer, 0, 1, 0}, /* 6 */
|
| + { OP_Noop, 0, 0, 0},
|
| + { OP_ResultRow, 1, 1, 0},
|
| + };
|
| + int addr;
|
| + sqlite3VdbeUsesBtree(v, iDb);
|
| + if( !zRight ){
|
| + setOneColumnName(v, "cache_size");
|
| + pParse->nMem += 2;
|
| + addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn);
|
| + sqlite3VdbeChangeP1(v, addr, iDb);
|
| + sqlite3VdbeChangeP1(v, addr+1, iDb);
|
| + sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
|
| + }else{
|
| + int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
|
| + sqlite3BeginWriteOperation(pParse, 0, iDb);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
|
| + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + pDb->pSchema->cache_size = size;
|
| + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
| + }
|
| + break;
|
| + }
|
| +#endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */
|
| +
|
| +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
| + /*
|
| + ** PRAGMA [schema.]page_size
|
| + ** PRAGMA [schema.]page_size=N
|
| + **
|
| + ** The first form reports the current setting for the
|
| + ** database page size in bytes. The second form sets the
|
| + ** database page size value. The value can only be set if
|
| + ** the database has not yet been created.
|
| + */
|
| + case PragTyp_PAGE_SIZE: {
|
| + Btree *pBt = pDb->pBt;
|
| + assert( pBt!=0 );
|
| + if( !zRight ){
|
| + int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
|
| + returnSingleInt(v, "page_size", size);
|
| + }else{
|
| + /* Malloc may fail when setting the page-size, as there is an internal
|
| + ** buffer that the pager module resizes using sqlite3_realloc().
|
| + */
|
| + db->nextPagesize = sqlite3Atoi(zRight);
|
| + if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
|
| + db->mallocFailed = 1;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]secure_delete
|
| + ** PRAGMA [schema.]secure_delete=ON/OFF
|
| + **
|
| + ** The first form reports the current setting for the
|
| + ** secure_delete flag. The second form changes the secure_delete
|
| + ** flag setting and reports thenew value.
|
| + */
|
| + case PragTyp_SECURE_DELETE: {
|
| + Btree *pBt = pDb->pBt;
|
| + int b = -1;
|
| + assert( pBt!=0 );
|
| + if( zRight ){
|
| + b = sqlite3GetBoolean(zRight, 0);
|
| + }
|
| + if( pId2->n==0 && b>=0 ){
|
| + int ii;
|
| + for(ii=0; ii<db->nDb; ii++){
|
| + sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b);
|
| + }
|
| + }
|
| + b = sqlite3BtreeSecureDelete(pBt, b);
|
| + returnSingleInt(v, "secure_delete", b);
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]max_page_count
|
| + ** PRAGMA [schema.]max_page_count=N
|
| + **
|
| + ** The first form reports the current setting for the
|
| + ** maximum number of pages in the database file. The
|
| + ** second form attempts to change this setting. Both
|
| + ** forms return the current setting.
|
| + **
|
| + ** The absolute value of N is used. This is undocumented and might
|
| + ** change. The only purpose is to provide an easy way to test
|
| + ** the sqlite3AbsInt32() function.
|
| + **
|
| + ** PRAGMA [schema.]page_count
|
| + **
|
| + ** Return the number of pages in the specified database.
|
| + */
|
| + case PragTyp_PAGE_COUNT: {
|
| + int iReg;
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + iReg = ++pParse->nMem;
|
| + if( sqlite3Tolower(zLeft[0])=='p' ){
|
| + sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
|
| + }else{
|
| + sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
|
| + sqlite3AbsInt32(sqlite3Atoi(zRight)));
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
|
| + sqlite3VdbeSetNumCols(v, 1);
|
| + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]locking_mode
|
| + ** PRAGMA [schema.]locking_mode = (normal|exclusive)
|
| + */
|
| + case PragTyp_LOCKING_MODE: {
|
| + const char *zRet = "normal";
|
| + int eMode = getLockingMode(zRight);
|
| +
|
| + if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){
|
| + /* Simple "PRAGMA locking_mode;" statement. This is a query for
|
| + ** the current default locking mode (which may be different to
|
| + ** the locking-mode of the main database).
|
| + */
|
| + eMode = db->dfltLockMode;
|
| + }else{
|
| + Pager *pPager;
|
| + if( pId2->n==0 ){
|
| + /* This indicates that no database name was specified as part
|
| + ** of the PRAGMA command. In this case the locking-mode must be
|
| + ** set on all attached databases, as well as the main db file.
|
| + **
|
| + ** Also, the sqlite3.dfltLockMode variable is set so that
|
| + ** any subsequently attached databases also use the specified
|
| + ** locking mode.
|
| + */
|
| + int ii;
|
| + assert(pDb==&db->aDb[0]);
|
| + for(ii=2; ii<db->nDb; ii++){
|
| + pPager = sqlite3BtreePager(db->aDb[ii].pBt);
|
| + sqlite3PagerLockingMode(pPager, eMode);
|
| + }
|
| + db->dfltLockMode = (u8)eMode;
|
| + }
|
| + pPager = sqlite3BtreePager(pDb->pBt);
|
| + eMode = sqlite3PagerLockingMode(pPager, eMode);
|
| + }
|
| +
|
| + assert( eMode==PAGER_LOCKINGMODE_NORMAL
|
| + || eMode==PAGER_LOCKINGMODE_EXCLUSIVE );
|
| + if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
|
| + zRet = "exclusive";
|
| + }
|
| + returnSingleText(v, "locking_mode", zRet);
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]journal_mode
|
| + ** PRAGMA [schema.]journal_mode =
|
| + ** (delete|persist|off|truncate|memory|wal|off)
|
| + */
|
| + case PragTyp_JOURNAL_MODE: {
|
| + int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
|
| + int ii; /* Loop counter */
|
| +
|
| + setOneColumnName(v, "journal_mode");
|
| + if( zRight==0 ){
|
| + /* If there is no "=MODE" part of the pragma, do a query for the
|
| + ** current mode */
|
| + eMode = PAGER_JOURNALMODE_QUERY;
|
| + }else{
|
| + const char *zMode;
|
| + int n = sqlite3Strlen30(zRight);
|
| + for(eMode=0; (zMode = sqlite3JournalModename(eMode))!=0; eMode++){
|
| + if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
|
| + }
|
| + if( !zMode ){
|
| + /* If the "=MODE" part does not match any known journal mode,
|
| + ** then do a query */
|
| + eMode = PAGER_JOURNALMODE_QUERY;
|
| + }
|
| + }
|
| + if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){
|
| + /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */
|
| + iDb = 0;
|
| + pId2->n = 1;
|
| + }
|
| + for(ii=db->nDb-1; ii>=0; ii--){
|
| + if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
|
| + sqlite3VdbeUsesBtree(v, ii);
|
| + sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
|
| + }
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]journal_size_limit
|
| + ** PRAGMA [schema.]journal_size_limit=N
|
| + **
|
| + ** Get or set the size limit on rollback journal files.
|
| + */
|
| + case PragTyp_JOURNAL_SIZE_LIMIT: {
|
| + Pager *pPager = sqlite3BtreePager(pDb->pBt);
|
| + i64 iLimit = -2;
|
| + if( zRight ){
|
| + sqlite3DecOrHexToI64(zRight, &iLimit);
|
| + if( iLimit<-1 ) iLimit = -1;
|
| + }
|
| + iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
|
| + returnSingleInt(v, "journal_size_limit", iLimit);
|
| + break;
|
| + }
|
| +
|
| +#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]auto_vacuum
|
| + ** PRAGMA [schema.]auto_vacuum=N
|
| + **
|
| + ** Get or set the value of the database 'auto-vacuum' parameter.
|
| + ** The value is one of: 0 NONE 1 FULL 2 INCREMENTAL
|
| + */
|
| +#ifndef SQLITE_OMIT_AUTOVACUUM
|
| + case PragTyp_AUTO_VACUUM: {
|
| + Btree *pBt = pDb->pBt;
|
| + assert( pBt!=0 );
|
| + if( !zRight ){
|
| + returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
|
| + }else{
|
| + int eAuto = getAutoVacuum(zRight);
|
| + assert( eAuto>=0 && eAuto<=2 );
|
| + db->nextAutovac = (u8)eAuto;
|
| + /* Call SetAutoVacuum() to set initialize the internal auto and
|
| + ** incr-vacuum flags. This is required in case this connection
|
| + ** creates the database file. It is important that it is created
|
| + ** as an auto-vacuum capable db.
|
| + */
|
| + rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
|
| + if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
|
| + /* When setting the auto_vacuum mode to either "full" or
|
| + ** "incremental", write the value of meta[6] in the database
|
| + ** file. Before writing to meta[6], check that meta[3] indicates
|
| + ** that this really is an auto-vacuum capable database.
|
| + */
|
| + static const int iLn = VDBE_OFFSET_LINENO(2);
|
| + static const VdbeOpList setMeta6[] = {
|
| + { OP_Transaction, 0, 1, 0}, /* 0 */
|
| + { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
|
| + { OP_If, 1, 0, 0}, /* 2 */
|
| + { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
|
| + { OP_Integer, 0, 1, 0}, /* 4 */
|
| + { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
|
| + };
|
| + int iAddr;
|
| + iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
|
| + sqlite3VdbeChangeP1(v, iAddr, iDb);
|
| + sqlite3VdbeChangeP1(v, iAddr+1, iDb);
|
| + sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
|
| + sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
|
| + sqlite3VdbeChangeP1(v, iAddr+5, iDb);
|
| + sqlite3VdbeUsesBtree(v, iDb);
|
| + }
|
| + }
|
| + break;
|
| + }
|
| +#endif
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]incremental_vacuum(N)
|
| + **
|
| + ** Do N steps of incremental vacuuming on a database.
|
| + */
|
| +#ifndef SQLITE_OMIT_AUTOVACUUM
|
| + case PragTyp_INCREMENTAL_VACUUM: {
|
| + int iLimit, addr;
|
| + if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
|
| + iLimit = 0x7fffffff;
|
| + }
|
| + sqlite3BeginWriteOperation(pParse, 0, iDb);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
|
| + addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp1(v, OP_ResultRow, 1);
|
| + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
| + sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addr);
|
| + break;
|
| + }
|
| +#endif
|
| +
|
| +#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
| + /*
|
| + ** PRAGMA [schema.]cache_size
|
| + ** PRAGMA [schema.]cache_size=N
|
| + **
|
| + ** The first form reports the current local setting for the
|
| + ** page cache size. The second form sets the local
|
| + ** page cache size value. If N is positive then that is the
|
| + ** number of pages in the cache. If N is negative, then the
|
| + ** number of pages is adjusted so that the cache uses -N kibibytes
|
| + ** of memory.
|
| + */
|
| + case PragTyp_CACHE_SIZE: {
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + if( !zRight ){
|
| + returnSingleInt(v, "cache_size", pDb->pSchema->cache_size);
|
| + }else{
|
| + int size = sqlite3Atoi(zRight);
|
| + pDb->pSchema->cache_size = size;
|
| + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]cache_spill
|
| + ** PRAGMA cache_spill=BOOLEAN
|
| + ** PRAGMA [schema.]cache_spill=N
|
| + **
|
| + ** The first form reports the current local setting for the
|
| + ** page cache spill size. The second form turns cache spill on
|
| + ** or off. When turnning cache spill on, the size is set to the
|
| + ** current cache_size. The third form sets a spill size that
|
| + ** may be different form the cache size.
|
| + ** If N is positive then that is the
|
| + ** number of pages in the cache. If N is negative, then the
|
| + ** number of pages is adjusted so that the cache uses -N kibibytes
|
| + ** of memory.
|
| + **
|
| + ** If the number of cache_spill pages is less then the number of
|
| + ** cache_size pages, no spilling occurs until the page count exceeds
|
| + ** the number of cache_size pages.
|
| + **
|
| + ** The cache_spill=BOOLEAN setting applies to all attached schemas,
|
| + ** not just the schema specified.
|
| + */
|
| + case PragTyp_CACHE_SPILL: {
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + if( !zRight ){
|
| + returnSingleInt(v, "cache_spill",
|
| + (db->flags & SQLITE_CacheSpill)==0 ? 0 :
|
| + sqlite3BtreeSetSpillSize(pDb->pBt,0));
|
| + }else{
|
| + int size = 1;
|
| + if( sqlite3GetInt32(zRight, &size) ){
|
| + sqlite3BtreeSetSpillSize(pDb->pBt, size);
|
| + }
|
| + if( sqlite3GetBoolean(zRight, size!=0) ){
|
| + db->flags |= SQLITE_CacheSpill;
|
| + }else{
|
| + db->flags &= ~SQLITE_CacheSpill;
|
| + }
|
| + setAllPagerFlags(db);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]mmap_size(N)
|
| + **
|
| + ** Used to set mapping size limit. The mapping size limit is
|
| + ** used to limit the aggregate size of all memory mapped regions of the
|
| + ** database file. If this parameter is set to zero, then memory mapping
|
| + ** is not used at all. If N is negative, then the default memory map
|
| + ** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_SIZE) is set.
|
| + ** The parameter N is measured in bytes.
|
| + **
|
| + ** This value is advisory. The underlying VFS is free to memory map
|
| + ** as little or as much as it wants. Except, if N is set to 0 then the
|
| + ** upper layers will never invoke the xFetch interfaces to the VFS.
|
| + */
|
| + case PragTyp_MMAP_SIZE: {
|
| + sqlite3_int64 sz;
|
| +#if SQLITE_MAX_MMAP_SIZE>0
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + if( zRight ){
|
| + int ii;
|
| + sqlite3DecOrHexToI64(zRight, &sz);
|
| + if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
|
| + if( pId2->n==0 ) db->szMmap = sz;
|
| + for(ii=db->nDb-1; ii>=0; ii--){
|
| + if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
|
| + sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz);
|
| + }
|
| + }
|
| + }
|
| + sz = -1;
|
| + rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_MMAP_SIZE, &sz);
|
| +#else
|
| + sz = 0;
|
| + rc = SQLITE_OK;
|
| +#endif
|
| + if( rc==SQLITE_OK ){
|
| + returnSingleInt(v, "mmap_size", sz);
|
| + }else if( rc!=SQLITE_NOTFOUND ){
|
| + pParse->nErr++;
|
| + pParse->rc = rc;
|
| + }
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA temp_store
|
| + ** PRAGMA temp_store = "default"|"memory"|"file"
|
| + **
|
| + ** Return or set the local value of the temp_store flag. Changing
|
| + ** the local value does not make changes to the disk file and the default
|
| + ** value will be restored the next time the database is opened.
|
| + **
|
| + ** Note that it is possible for the library compile-time options to
|
| + ** override this setting
|
| + */
|
| + case PragTyp_TEMP_STORE: {
|
| + if( !zRight ){
|
| + returnSingleInt(v, "temp_store", db->temp_store);
|
| + }else{
|
| + changeTempStorage(pParse, zRight);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA temp_store_directory
|
| + ** PRAGMA temp_store_directory = ""|"directory_name"
|
| + **
|
| + ** Return or set the local value of the temp_store_directory flag. Changing
|
| + ** the value sets a specific directory to be used for temporary files.
|
| + ** Setting to a null string reverts to the default temporary directory search.
|
| + ** If temporary directory is changed, then invalidateTempStorage.
|
| + **
|
| + */
|
| + case PragTyp_TEMP_STORE_DIRECTORY: {
|
| + if( !zRight ){
|
| + returnSingleText(v, "temp_store_directory", sqlite3_temp_directory);
|
| + }else{
|
| +#ifndef SQLITE_OMIT_WSD
|
| + if( zRight[0] ){
|
| + int res;
|
| + rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
|
| + if( rc!=SQLITE_OK || res==0 ){
|
| + sqlite3ErrorMsg(pParse, "not a writable directory");
|
| + goto pragma_out;
|
| + }
|
| + }
|
| + if( SQLITE_TEMP_STORE==0
|
| + || (SQLITE_TEMP_STORE==1 && db->temp_store<=1)
|
| + || (SQLITE_TEMP_STORE==2 && db->temp_store==1)
|
| + ){
|
| + invalidateTempStorage(pParse);
|
| + }
|
| + sqlite3_free(sqlite3_temp_directory);
|
| + if( zRight[0] ){
|
| + sqlite3_temp_directory = sqlite3_mprintf("%s", zRight);
|
| + }else{
|
| + sqlite3_temp_directory = 0;
|
| + }
|
| +#endif /* SQLITE_OMIT_WSD */
|
| + }
|
| + break;
|
| + }
|
| +
|
| +#if SQLITE_OS_WIN
|
| + /*
|
| + ** PRAGMA data_store_directory
|
| + ** PRAGMA data_store_directory = ""|"directory_name"
|
| + **
|
| + ** Return or set the local value of the data_store_directory flag. Changing
|
| + ** the value sets a specific directory to be used for database files that
|
| + ** were specified with a relative pathname. Setting to a null string reverts
|
| + ** to the default database directory, which for database files specified with
|
| + ** a relative path will probably be based on the current directory for the
|
| + ** process. Database file specified with an absolute path are not impacted
|
| + ** by this setting, regardless of its value.
|
| + **
|
| + */
|
| + case PragTyp_DATA_STORE_DIRECTORY: {
|
| + if( !zRight ){
|
| + returnSingleText(v, "data_store_directory", sqlite3_data_directory);
|
| + }else{
|
| +#ifndef SQLITE_OMIT_WSD
|
| + if( zRight[0] ){
|
| + int res;
|
| + rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
|
| + if( rc!=SQLITE_OK || res==0 ){
|
| + sqlite3ErrorMsg(pParse, "not a writable directory");
|
| + goto pragma_out;
|
| + }
|
| + }
|
| + sqlite3_free(sqlite3_data_directory);
|
| + if( zRight[0] ){
|
| + sqlite3_data_directory = sqlite3_mprintf("%s", zRight);
|
| + }else{
|
| + sqlite3_data_directory = 0;
|
| + }
|
| +#endif /* SQLITE_OMIT_WSD */
|
| + }
|
| + break;
|
| + }
|
| +#endif
|
| +
|
| +#if SQLITE_ENABLE_LOCKING_STYLE
|
| + /*
|
| + ** PRAGMA [schema.]lock_proxy_file
|
| + ** PRAGMA [schema.]lock_proxy_file = ":auto:"|"lock_file_path"
|
| + **
|
| + ** Return or set the value of the lock_proxy_file flag. Changing
|
| + ** the value sets a specific file to be used for database access locks.
|
| + **
|
| + */
|
| + case PragTyp_LOCK_PROXY_FILE: {
|
| + if( !zRight ){
|
| + Pager *pPager = sqlite3BtreePager(pDb->pBt);
|
| + char *proxy_file_path = NULL;
|
| + sqlite3_file *pFile = sqlite3PagerFile(pPager);
|
| + sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
|
| + &proxy_file_path);
|
| + returnSingleText(v, "lock_proxy_file", proxy_file_path);
|
| + }else{
|
| + Pager *pPager = sqlite3BtreePager(pDb->pBt);
|
| + sqlite3_file *pFile = sqlite3PagerFile(pPager);
|
| + int res;
|
| + if( zRight[0] ){
|
| + res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
|
| + zRight);
|
| + } else {
|
| + res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
|
| + NULL);
|
| + }
|
| + if( res!=SQLITE_OK ){
|
| + sqlite3ErrorMsg(pParse, "failed to set lock proxy file");
|
| + goto pragma_out;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| +#endif /* SQLITE_ENABLE_LOCKING_STYLE */
|
| +
|
| + /*
|
| + ** PRAGMA [schema.]synchronous
|
| + ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL
|
| + **
|
| + ** Return or set the local value of the synchronous flag. Changing
|
| + ** the local value does not make changes to the disk file and the
|
| + ** default value will be restored the next time the database is
|
| + ** opened.
|
| + */
|
| + case PragTyp_SYNCHRONOUS: {
|
| + if( !zRight ){
|
| + returnSingleInt(v, "synchronous", pDb->safety_level-1);
|
| + }else{
|
| + if( !db->autoCommit ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "Safety level may not be changed inside a transaction");
|
| + }else{
|
| + int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
|
| + if( iLevel==0 ) iLevel = 1;
|
| + pDb->safety_level = iLevel;
|
| + setAllPagerFlags(db);
|
| + }
|
| + }
|
| + break;
|
| + }
|
| +#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
| +
|
| +#ifndef SQLITE_OMIT_FLAG_PRAGMAS
|
| + case PragTyp_FLAG: {
|
| + if( zRight==0 ){
|
| + returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
|
| + }else{
|
| + int mask = pPragma->iArg; /* Mask of bits to set or clear. */
|
| + if( db->autoCommit==0 ){
|
| + /* Foreign key support may not be enabled or disabled while not
|
| + ** in auto-commit mode. */
|
| + mask &= ~(SQLITE_ForeignKeys);
|
| + }
|
| +#if SQLITE_USER_AUTHENTICATION
|
| + if( db->auth.authLevel==UAUTH_User ){
|
| + /* Do not allow non-admin users to modify the schema arbitrarily */
|
| + mask &= ~(SQLITE_WriteSchema);
|
| + }
|
| +#endif
|
| +
|
| + if( sqlite3GetBoolean(zRight, 0) ){
|
| + db->flags |= mask;
|
| + }else{
|
| + db->flags &= ~mask;
|
| + if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
|
| + }
|
| +
|
| + /* Many of the flag-pragmas modify the code generated by the SQL
|
| + ** compiler (eg. count_changes). So add an opcode to expire all
|
| + ** compiled SQL statements after modifying a pragma value.
|
| + */
|
| + sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
|
| + setAllPagerFlags(db);
|
| + }
|
| + break;
|
| + }
|
| +#endif /* SQLITE_OMIT_FLAG_PRAGMAS */
|
| +
|
| +#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
|
| + /*
|
| + ** PRAGMA table_info(<table>)
|
| + **
|
| + ** Return a single row for each column of the named table. The columns of
|
| + ** the returned data set are:
|
| + **
|
| + ** cid: Column id (numbered from left to right, starting at 0)
|
| + ** name: Column name
|
| + ** type: Column declaration type.
|
| + ** notnull: True if 'NOT NULL' is part of column declaration
|
| + ** dflt_value: The default value for the column, if any.
|
| + */
|
| + case PragTyp_TABLE_INFO: if( zRight ){
|
| + Table *pTab;
|
| + pTab = sqlite3FindTable(db, zRight, zDb);
|
| + if( pTab ){
|
| + static const char *azCol[] = {
|
| + "cid", "name", "type", "notnull", "dflt_value", "pk"
|
| + };
|
| + int i, k;
|
| + int nHidden = 0;
|
| + Column *pCol;
|
| + Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
| + pParse->nMem = 6;
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
|
| + sqlite3ViewGetColumnNames(pParse, pTab);
|
| + for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
| + if( IsHiddenColumn(pCol) ){
|
| + nHidden++;
|
| + continue;
|
| + }
|
| + if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
|
| + k = 0;
|
| + }else if( pPk==0 ){
|
| + k = 1;
|
| + }else{
|
| + for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
|
| + }
|
| + sqlite3VdbeMultiLoad(v, 1, "issisi",
|
| + i-nHidden,
|
| + pCol->zName,
|
| + pCol->zType ? pCol->zType : "",
|
| + pCol->notNull ? 1 : 0,
|
| + pCol->zDflt,
|
| + k);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
|
| + }
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case PragTyp_STATS: {
|
| + static const char *azCol[] = { "table", "index", "width", "height" };
|
| + Index *pIdx;
|
| + HashElem *i;
|
| + v = sqlite3GetVdbe(pParse);
|
| + pParse->nMem = 4;
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
|
| + for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
|
| + Table *pTab = sqliteHashData(i);
|
| + sqlite3VdbeMultiLoad(v, 1, "ssii",
|
| + pTab->zName,
|
| + 0,
|
| + (int)sqlite3LogEstToInt(pTab->szTabRow),
|
| + (int)sqlite3LogEstToInt(pTab->nRowLogEst));
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + sqlite3VdbeMultiLoad(v, 2, "sii",
|
| + pIdx->zName,
|
| + (int)sqlite3LogEstToInt(pIdx->szIdxRow),
|
| + (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]));
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
| + }
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case PragTyp_INDEX_INFO: if( zRight ){
|
| + Index *pIdx;
|
| + Table *pTab;
|
| + pIdx = sqlite3FindIndex(db, zRight, zDb);
|
| + if( pIdx ){
|
| + static const char *azCol[] = {
|
| + "seqno", "cid", "name", "desc", "coll", "key"
|
| + };
|
| + int i;
|
| + int mx;
|
| + if( pPragma->iArg ){
|
| + /* PRAGMA index_xinfo (newer version with more rows and columns) */
|
| + mx = pIdx->nColumn;
|
| + pParse->nMem = 6;
|
| + }else{
|
| + /* PRAGMA index_info (legacy version) */
|
| + mx = pIdx->nKeyCol;
|
| + pParse->nMem = 3;
|
| + }
|
| + pTab = pIdx->pTable;
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + assert( pParse->nMem<=ArraySize(azCol) );
|
| + setAllColumnNames(v, pParse->nMem, azCol);
|
| + for(i=0; i<mx; i++){
|
| + i16 cnum = pIdx->aiColumn[i];
|
| + sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum,
|
| + cnum<0 ? 0 : pTab->aCol[cnum].zName);
|
| + if( pPragma->iArg ){
|
| + sqlite3VdbeMultiLoad(v, 4, "isi",
|
| + pIdx->aSortOrder[i],
|
| + pIdx->azColl[i],
|
| + i<pIdx->nKeyCol);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem);
|
| + }
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case PragTyp_INDEX_LIST: if( zRight ){
|
| + Index *pIdx;
|
| + Table *pTab;
|
| + int i;
|
| + pTab = sqlite3FindTable(db, zRight, zDb);
|
| + if( pTab ){
|
| + static const char *azCol[] = {
|
| + "seq", "name", "unique", "origin", "partial"
|
| + };
|
| + v = sqlite3GetVdbe(pParse);
|
| + pParse->nMem = 5;
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + setAllColumnNames(v, 5, azCol); assert( 5==ArraySize(azCol) );
|
| + for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
|
| + const char *azOrigin[] = { "c", "u", "pk" };
|
| + sqlite3VdbeMultiLoad(v, 1, "isisi",
|
| + i,
|
| + pIdx->zName,
|
| + IsUniqueIndex(pIdx),
|
| + azOrigin[pIdx->idxType],
|
| + pIdx->pPartIdxWhere!=0);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
|
| + }
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case PragTyp_DATABASE_LIST: {
|
| + static const char *azCol[] = { "seq", "name", "file" };
|
| + int i;
|
| + pParse->nMem = 3;
|
| + setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
|
| + for(i=0; i<db->nDb; i++){
|
| + if( db->aDb[i].pBt==0 ) continue;
|
| + assert( db->aDb[i].zName!=0 );
|
| + sqlite3VdbeMultiLoad(v, 1, "iss",
|
| + i,
|
| + db->aDb[i].zName,
|
| + sqlite3BtreeGetFilename(db->aDb[i].pBt));
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case PragTyp_COLLATION_LIST: {
|
| + static const char *azCol[] = { "seq", "name" };
|
| + int i = 0;
|
| + HashElem *p;
|
| + pParse->nMem = 2;
|
| + setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
|
| + for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
|
| + CollSeq *pColl = (CollSeq *)sqliteHashData(p);
|
| + sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
|
| + }
|
| + }
|
| + break;
|
| +#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
|
| +
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| + case PragTyp_FOREIGN_KEY_LIST: if( zRight ){
|
| + FKey *pFK;
|
| + Table *pTab;
|
| + pTab = sqlite3FindTable(db, zRight, zDb);
|
| + if( pTab ){
|
| + v = sqlite3GetVdbe(pParse);
|
| + pFK = pTab->pFKey;
|
| + if( pFK ){
|
| + static const char *azCol[] = {
|
| + "id", "seq", "table", "from", "to", "on_update", "on_delete",
|
| + "match"
|
| + };
|
| + int i = 0;
|
| + pParse->nMem = 8;
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + setAllColumnNames(v, 8, azCol); assert( 8==ArraySize(azCol) );
|
| + while(pFK){
|
| + int j;
|
| + for(j=0; j<pFK->nCol; j++){
|
| + sqlite3VdbeMultiLoad(v, 1, "iissssss",
|
| + i,
|
| + j,
|
| + pFK->zTo,
|
| + pTab->aCol[pFK->aCol[j].iFrom].zName,
|
| + pFK->aCol[j].zCol,
|
| + actionName(pFK->aAction[1]), /* ON UPDATE */
|
| + actionName(pFK->aAction[0]), /* ON DELETE */
|
| + "NONE");
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8);
|
| + }
|
| + ++i;
|
| + pFK = pFK->pNextFrom;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + break;
|
| +#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
|
| +
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| +#ifndef SQLITE_OMIT_TRIGGER
|
| + case PragTyp_FOREIGN_KEY_CHECK: {
|
| + FKey *pFK; /* A foreign key constraint */
|
| + Table *pTab; /* Child table contain "REFERENCES" keyword */
|
| + Table *pParent; /* Parent table that child points to */
|
| + Index *pIdx; /* Index in the parent table */
|
| + int i; /* Loop counter: Foreign key number for pTab */
|
| + int j; /* Loop counter: Field of the foreign key */
|
| + HashElem *k; /* Loop counter: Next table in schema */
|
| + int x; /* result variable */
|
| + int regResult; /* 3 registers to hold a result row */
|
| + int regKey; /* Register to hold key for checking the FK */
|
| + int regRow; /* Registers to hold a row from pTab */
|
| + int addrTop; /* Top of a loop checking foreign keys */
|
| + int addrOk; /* Jump here if the key is OK */
|
| + int *aiCols; /* child to parent column mapping */
|
| + static const char *azCol[] = { "table", "rowid", "parent", "fkid" };
|
| +
|
| + regResult = pParse->nMem+1;
|
| + pParse->nMem += 4;
|
| + regKey = ++pParse->nMem;
|
| + regRow = ++pParse->nMem;
|
| + v = sqlite3GetVdbe(pParse);
|
| + setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
|
| + while( k ){
|
| + if( zRight ){
|
| + pTab = sqlite3LocateTable(pParse, 0, zRight, zDb);
|
| + k = 0;
|
| + }else{
|
| + pTab = (Table*)sqliteHashData(k);
|
| + k = sqliteHashNext(k);
|
| + }
|
| + if( pTab==0 || pTab->pFKey==0 ) continue;
|
| + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
| + if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
|
| + sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
|
| + sqlite3VdbeLoadString(v, regResult, pTab->zName);
|
| + for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
| + pParent = sqlite3FindTable(db, pFK->zTo, zDb);
|
| + if( pParent==0 ) continue;
|
| + pIdx = 0;
|
| + sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName);
|
| + x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0);
|
| + if( x==0 ){
|
| + if( pIdx==0 ){
|
| + sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead);
|
| + }else{
|
| + sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb);
|
| + sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
| + }
|
| + }else{
|
| + k = 0;
|
| + break;
|
| + }
|
| + }
|
| + assert( pParse->nErr>0 || pFK==0 );
|
| + if( pFK ) break;
|
| + if( pParse->nTab<i ) pParse->nTab = i;
|
| + addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v);
|
| + for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
| + pParent = sqlite3FindTable(db, pFK->zTo, zDb);
|
| + pIdx = 0;
|
| + aiCols = 0;
|
| + if( pParent ){
|
| + x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
|
| + assert( x==0 );
|
| + }
|
| + addrOk = sqlite3VdbeMakeLabel(v);
|
| + if( pParent && pIdx==0 ){
|
| + int iKey = pFK->aCol[0].iFrom;
|
| + assert( iKey>=0 && iKey<pTab->nCol );
|
| + if( iKey!=pTab->iPKey ){
|
| + sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
|
| + sqlite3ColumnDefault(v, pTab, iKey, regRow);
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow,
|
| + sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v);
|
| + }else{
|
| + sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v);
|
| + sqlite3VdbeGoto(v, addrOk);
|
| + sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
| + }else{
|
| + for(j=0; j<pFK->nCol; j++){
|
| + sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
|
| + aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
|
| + }
|
| + if( pParent ){
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
|
| + sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
|
| + sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
| + VdbeCoverage(v);
|
| + }
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
|
| + sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
|
| + sqlite3VdbeResolveLabel(v, addrOk);
|
| + sqlite3DbFree(db, aiCols);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addrTop);
|
| + }
|
| + }
|
| + break;
|
| +#endif /* !defined(SQLITE_OMIT_TRIGGER) */
|
| +#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
|
| +
|
| +#ifndef NDEBUG
|
| + case PragTyp_PARSER_TRACE: {
|
| + if( zRight ){
|
| + if( sqlite3GetBoolean(zRight, 0) ){
|
| + sqlite3ParserTrace(stdout, "parser: ");
|
| + }else{
|
| + sqlite3ParserTrace(0, 0);
|
| + }
|
| + }
|
| + }
|
| + break;
|
| +#endif
|
| +
|
| + /* Reinstall the LIKE and GLOB functions. The variant of LIKE
|
| + ** used will be case sensitive or not depending on the RHS.
|
| + */
|
| + case PragTyp_CASE_SENSITIVE_LIKE: {
|
| + if( zRight ){
|
| + sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight, 0));
|
| + }
|
| + }
|
| + break;
|
| +
|
| +#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
|
| +# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
|
| +#endif
|
| +
|
| +#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
| + /* Pragma "quick_check" is reduced version of
|
| + ** integrity_check designed to detect most database corruption
|
| + ** without most of the overhead of a full integrity-check.
|
| + */
|
| + case PragTyp_INTEGRITY_CHECK: {
|
| + int i, j, addr, mxErr;
|
| +
|
| + /* Code that appears at the end of the integrity check. If no error
|
| + ** messages have been generated, output OK. Otherwise output the
|
| + ** error message
|
| + */
|
| + static const int iLn = VDBE_OFFSET_LINENO(2);
|
| + static const VdbeOpList endCode[] = {
|
| + { OP_AddImm, 1, 0, 0}, /* 0 */
|
| + { OP_If, 1, 0, 0}, /* 1 */
|
| + { OP_String8, 0, 3, 0}, /* 2 */
|
| + { OP_ResultRow, 3, 1, 0},
|
| + };
|
| +
|
| + int isQuick = (sqlite3Tolower(zLeft[0])=='q');
|
| +
|
| + /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
|
| + ** then iDb is set to the index of the database identified by <db>.
|
| + ** In this case, the integrity of database iDb only is verified by
|
| + ** the VDBE created below.
|
| + **
|
| + ** Otherwise, if the command was simply "PRAGMA integrity_check" (or
|
| + ** "PRAGMA quick_check"), then iDb is set to 0. In this case, set iDb
|
| + ** to -1 here, to indicate that the VDBE should verify the integrity
|
| + ** of all attached databases. */
|
| + assert( iDb>=0 );
|
| + assert( iDb==0 || pId2->z );
|
| + if( pId2->z==0 ) iDb = -1;
|
| +
|
| + /* Initialize the VDBE program */
|
| + pParse->nMem = 6;
|
| + setOneColumnName(v, "integrity_check");
|
| +
|
| + /* Set the maximum error count */
|
| + mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
| + if( zRight ){
|
| + sqlite3GetInt32(zRight, &mxErr);
|
| + if( mxErr<=0 ){
|
| + mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
| + }
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */
|
| +
|
| + /* Do an integrity check on each database file */
|
| + for(i=0; i<db->nDb; i++){
|
| + HashElem *x;
|
| + Hash *pTbls;
|
| + int cnt = 0;
|
| +
|
| + if( OMIT_TEMPDB && i==1 ) continue;
|
| + if( iDb>=0 && i!=iDb ) continue;
|
| +
|
| + sqlite3CodeVerifySchema(pParse, i);
|
| + addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
|
| + VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
| + sqlite3VdbeJumpHere(v, addr);
|
| +
|
| + /* Do an integrity check of the B-Tree
|
| + **
|
| + ** Begin by filling registers 2, 3, ... with the root pages numbers
|
| + ** for all tables and indices in the database.
|
| + */
|
| + assert( sqlite3SchemaMutexHeld(db, i, 0) );
|
| + pTbls = &db->aDb[i].pSchema->tblHash;
|
| + for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
| + Table *pTab = sqliteHashData(x);
|
| + Index *pIdx;
|
| + if( HasRowid(pTab) ){
|
| + sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
|
| + VdbeComment((v, "%s", pTab->zName));
|
| + cnt++;
|
| + }
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
|
| + VdbeComment((v, "%s", pIdx->zName));
|
| + cnt++;
|
| + }
|
| + }
|
| +
|
| + /* Make sure sufficient number of registers have been allocated */
|
| + pParse->nMem = MAX( pParse->nMem, cnt+8 );
|
| +
|
| + /* Do the b-tree integrity checks */
|
| + sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
|
| + sqlite3VdbeChangeP5(v, (u8)i);
|
| + addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
| + sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
|
| + P4_DYNAMIC);
|
| + sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
|
| + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
|
| + sqlite3VdbeJumpHere(v, addr);
|
| +
|
| + /* Make sure all the indices are constructed correctly.
|
| + */
|
| + for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
|
| + Table *pTab = sqliteHashData(x);
|
| + Index *pIdx, *pPk;
|
| + Index *pPrior = 0;
|
| + int loopTop;
|
| + int iDataCur, iIdxCur;
|
| + int r1 = -1;
|
| +
|
| + if( pTab->pIndex==0 ) continue;
|
| + pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
| + addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
|
| + VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
| + sqlite3VdbeJumpHere(v, addr);
|
| + sqlite3ExprCacheClear(pParse);
|
| + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
|
| + 1, 0, &iDataCur, &iIdxCur);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
|
| + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
|
| + }
|
| + pParse->nMem = MAX(pParse->nMem, 8+j);
|
| + sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
|
| + loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
|
| + /* Verify that all NOT NULL columns really are NOT NULL */
|
| + for(j=0; j<pTab->nCol; j++){
|
| + char *zErr;
|
| + int jmp2, jmp3;
|
| + if( j==pTab->iPKey ) continue;
|
| + if( pTab->aCol[j].notNull==0 ) continue;
|
| + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
|
| + jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
| + zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
|
| + pTab->aCol[j].zName);
|
| + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
|
| + jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp0(v, OP_Halt);
|
| + sqlite3VdbeJumpHere(v, jmp2);
|
| + sqlite3VdbeJumpHere(v, jmp3);
|
| + }
|
| + /* Validate index entries for the current row */
|
| + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
| + int jmp2, jmp3, jmp4, jmp5;
|
| + int ckUniq = sqlite3VdbeMakeLabel(v);
|
| + if( pPk==pIdx ) continue;
|
| + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
|
| + pPrior, r1);
|
| + pPrior = pIdx;
|
| + sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
|
| + /* Verify that an index entry exists for the current table row */
|
| + jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
|
| + pIdx->nColumn); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
| + sqlite3VdbeLoadString(v, 3, "row ");
|
| + sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
| + sqlite3VdbeLoadString(v, 4, " missing from index ");
|
| + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
| + jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
|
| + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
|
| + jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp0(v, OP_Halt);
|
| + sqlite3VdbeJumpHere(v, jmp2);
|
| + /* For UNIQUE indexes, verify that only one entry exists with the
|
| + ** current key. The entry is unique if (1) any column is NULL
|
| + ** or (2) the next entry has a different key */
|
| + if( IsUniqueIndex(pIdx) ){
|
| + int uniqOk = sqlite3VdbeMakeLabel(v);
|
| + int jmp6;
|
| + int kk;
|
| + for(kk=0; kk<pIdx->nKeyCol; kk++){
|
| + int iCol = pIdx->aiColumn[kk];
|
| + assert( iCol!=XN_ROWID && iCol<pTab->nCol );
|
| + if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
|
| + VdbeCoverage(v);
|
| + }
|
| + jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
|
| + sqlite3VdbeGoto(v, uniqOk);
|
| + sqlite3VdbeJumpHere(v, jmp6);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
|
| + pIdx->nKeyCol); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
| + sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
|
| + sqlite3VdbeGoto(v, jmp5);
|
| + sqlite3VdbeResolveLabel(v, uniqOk);
|
| + }
|
| + sqlite3VdbeJumpHere(v, jmp4);
|
| + sqlite3ResolvePartIdxLabel(pParse, jmp3);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, loopTop-1);
|
| +#ifndef SQLITE_OMIT_BTREECOUNT
|
| + sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
|
| + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
| + if( pPk==pIdx ) continue;
|
| + addr = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
| + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
|
| + sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
|
| + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
| + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
| + sqlite3VdbeLoadString(v, 3, pIdx->zName);
|
| + sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
|
| + }
|
| +#endif /* SQLITE_OMIT_BTREECOUNT */
|
| + }
|
| + }
|
| + addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
|
| + sqlite3VdbeChangeP2(v, addr, -mxErr);
|
| + sqlite3VdbeJumpHere(v, addr+1);
|
| + sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
|
| + }
|
| + break;
|
| +#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
| +
|
| +#ifndef SQLITE_OMIT_UTF16
|
| + /*
|
| + ** PRAGMA encoding
|
| + ** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
|
| + **
|
| + ** In its first form, this pragma returns the encoding of the main
|
| + ** database. If the database is not initialized, it is initialized now.
|
| + **
|
| + ** The second form of this pragma is a no-op if the main database file
|
| + ** has not already been initialized. In this case it sets the default
|
| + ** encoding that will be used for the main database file if a new file
|
| + ** is created. If an existing main database file is opened, then the
|
| + ** default text encoding for the existing database is used.
|
| + **
|
| + ** In all cases new databases created using the ATTACH command are
|
| + ** created to use the same default text encoding as the main database. If
|
| + ** the main database has not been initialized and/or created when ATTACH
|
| + ** is executed, this is done before the ATTACH operation.
|
| + **
|
| + ** In the second form this pragma sets the text encoding to be used in
|
| + ** new database files created using this database handle. It is only
|
| + ** useful if invoked immediately after the main database i
|
| + */
|
| + case PragTyp_ENCODING: {
|
| + static const struct EncName {
|
| + char *zName;
|
| + u8 enc;
|
| + } encnames[] = {
|
| + { "UTF8", SQLITE_UTF8 },
|
| + { "UTF-8", SQLITE_UTF8 }, /* Must be element [1] */
|
| + { "UTF-16le", SQLITE_UTF16LE }, /* Must be element [2] */
|
| + { "UTF-16be", SQLITE_UTF16BE }, /* Must be element [3] */
|
| + { "UTF16le", SQLITE_UTF16LE },
|
| + { "UTF16be", SQLITE_UTF16BE },
|
| + { "UTF-16", 0 }, /* SQLITE_UTF16NATIVE */
|
| + { "UTF16", 0 }, /* SQLITE_UTF16NATIVE */
|
| + { 0, 0 }
|
| + };
|
| + const struct EncName *pEnc;
|
| + if( !zRight ){ /* "PRAGMA encoding" */
|
| + if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
| + assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 );
|
| + assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE );
|
| + assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE );
|
| + returnSingleText(v, "encoding", encnames[ENC(pParse->db)].zName);
|
| + }else{ /* "PRAGMA encoding = XXX" */
|
| + /* Only change the value of sqlite.enc if the database handle is not
|
| + ** initialized. If the main database exists, the new sqlite.enc value
|
| + ** will be overwritten when the schema is next loaded. If it does not
|
| + ** already exists, it will be created to use the new encoding value.
|
| + */
|
| + if(
|
| + !(DbHasProperty(db, 0, DB_SchemaLoaded)) ||
|
| + DbHasProperty(db, 0, DB_Empty)
|
| + ){
|
| + for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
| + if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
|
| + SCHEMA_ENC(db) = ENC(db) =
|
| + pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
|
| + break;
|
| + }
|
| + }
|
| + if( !pEnc->zName ){
|
| + sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + break;
|
| +#endif /* SQLITE_OMIT_UTF16 */
|
| +
|
| +#ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
|
| + /*
|
| + ** PRAGMA [schema.]schema_version
|
| + ** PRAGMA [schema.]schema_version = <integer>
|
| + **
|
| + ** PRAGMA [schema.]user_version
|
| + ** PRAGMA [schema.]user_version = <integer>
|
| + **
|
| + ** PRAGMA [schema.]freelist_count = <integer>
|
| + **
|
| + ** PRAGMA [schema.]application_id
|
| + ** PRAGMA [schema.]application_id = <integer>
|
| + **
|
| + ** The pragma's schema_version and user_version are used to set or get
|
| + ** the value of the schema-version and user-version, respectively. Both
|
| + ** the schema-version and the user-version are 32-bit signed integers
|
| + ** stored in the database header.
|
| + **
|
| + ** The schema-cookie is usually only manipulated internally by SQLite. It
|
| + ** is incremented by SQLite whenever the database schema is modified (by
|
| + ** creating or dropping a table or index). The schema version is used by
|
| + ** SQLite each time a query is executed to ensure that the internal cache
|
| + ** of the schema used when compiling the SQL query matches the schema of
|
| + ** the database against which the compiled query is actually executed.
|
| + ** Subverting this mechanism by using "PRAGMA schema_version" to modify
|
| + ** the schema-version is potentially dangerous and may lead to program
|
| + ** crashes or database corruption. Use with caution!
|
| + **
|
| + ** The user-version is not used internally by SQLite. It may be used by
|
| + ** applications for any purpose.
|
| + */
|
| + case PragTyp_HEADER_VALUE: {
|
| + int iCookie = pPragma->iArg; /* Which cookie to read or write */
|
| + sqlite3VdbeUsesBtree(v, iDb);
|
| + if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
|
| + /* Write the specified cookie value */
|
| + static const VdbeOpList setCookie[] = {
|
| + { OP_Transaction, 0, 1, 0}, /* 0 */
|
| + { OP_Integer, 0, 1, 0}, /* 1 */
|
| + { OP_SetCookie, 0, 0, 1}, /* 2 */
|
| + };
|
| + int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
|
| + sqlite3VdbeChangeP1(v, addr, iDb);
|
| + sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
|
| + sqlite3VdbeChangeP1(v, addr+2, iDb);
|
| + sqlite3VdbeChangeP2(v, addr+2, iCookie);
|
| + }else{
|
| + /* Read the specified cookie value */
|
| + static const VdbeOpList readCookie[] = {
|
| + { OP_Transaction, 0, 0, 0}, /* 0 */
|
| + { OP_ReadCookie, 0, 1, 0}, /* 1 */
|
| + { OP_ResultRow, 1, 1, 0}
|
| + };
|
| + int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0);
|
| + sqlite3VdbeChangeP1(v, addr, iDb);
|
| + sqlite3VdbeChangeP1(v, addr+1, iDb);
|
| + sqlite3VdbeChangeP3(v, addr+1, iCookie);
|
| + sqlite3VdbeSetNumCols(v, 1);
|
| + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
|
| + }
|
| + }
|
| + break;
|
| +#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
|
| +
|
| +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
| + /*
|
| + ** PRAGMA compile_options
|
| + **
|
| + ** Return the names of all compile-time options used in this build,
|
| + ** one option per row.
|
| + */
|
| + case PragTyp_COMPILE_OPTIONS: {
|
| + int i = 0;
|
| + const char *zOpt;
|
| + pParse->nMem = 1;
|
| + setOneColumnName(v, "compile_option");
|
| + while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
|
| + sqlite3VdbeLoadString(v, 1, zOpt);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
| + }
|
| + }
|
| + break;
|
| +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
| +
|
| +#ifndef SQLITE_OMIT_WAL
|
| + /*
|
| + ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate
|
| + **
|
| + ** Checkpoint the database.
|
| + */
|
| + case PragTyp_WAL_CHECKPOINT: {
|
| + static const char *azCol[] = { "busy", "log", "checkpointed" };
|
| + int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
|
| + int eMode = SQLITE_CHECKPOINT_PASSIVE;
|
| + if( zRight ){
|
| + if( sqlite3StrICmp(zRight, "full")==0 ){
|
| + eMode = SQLITE_CHECKPOINT_FULL;
|
| + }else if( sqlite3StrICmp(zRight, "restart")==0 ){
|
| + eMode = SQLITE_CHECKPOINT_RESTART;
|
| + }else if( sqlite3StrICmp(zRight, "truncate")==0 ){
|
| + eMode = SQLITE_CHECKPOINT_TRUNCATE;
|
| + }
|
| + }
|
| + setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
|
| + pParse->nMem = 3;
|
| + sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
|
| + }
|
| + break;
|
| +
|
| + /*
|
| + ** PRAGMA wal_autocheckpoint
|
| + ** PRAGMA wal_autocheckpoint = N
|
| + **
|
| + ** Configure a database connection to automatically checkpoint a database
|
| + ** after accumulating N frames in the log. Or query for the current value
|
| + ** of N.
|
| + */
|
| + case PragTyp_WAL_AUTOCHECKPOINT: {
|
| + if( zRight ){
|
| + sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
|
| + }
|
| + returnSingleInt(v, "wal_autocheckpoint",
|
| + db->xWalCallback==sqlite3WalDefaultHook ?
|
| + SQLITE_PTR_TO_INT(db->pWalArg) : 0);
|
| + }
|
| + break;
|
| +#endif
|
| +
|
| + /*
|
| + ** PRAGMA shrink_memory
|
| + **
|
| + ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database
|
| + ** connection on which it is invoked to free up as much memory as it
|
| + ** can, by calling sqlite3_db_release_memory().
|
| + */
|
| + case PragTyp_SHRINK_MEMORY: {
|
| + sqlite3_db_release_memory(db);
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA busy_timeout
|
| + ** PRAGMA busy_timeout = N
|
| + **
|
| + ** Call sqlite3_busy_timeout(db, N). Return the current timeout value
|
| + ** if one is set. If no busy handler or a different busy handler is set
|
| + ** then 0 is returned. Setting the busy_timeout to 0 or negative
|
| + ** disables the timeout.
|
| + */
|
| + /*case PragTyp_BUSY_TIMEOUT*/ default: {
|
| + assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT );
|
| + if( zRight ){
|
| + sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
|
| + }
|
| + returnSingleInt(v, "timeout", db->busyTimeout);
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA soft_heap_limit
|
| + ** PRAGMA soft_heap_limit = N
|
| + **
|
| + ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the
|
| + ** sqlite3_soft_heap_limit64() interface with the argument N, if N is
|
| + ** specified and is a non-negative integer.
|
| + ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always
|
| + ** returns the same integer that would be returned by the
|
| + ** sqlite3_soft_heap_limit64(-1) C-language function.
|
| + */
|
| + case PragTyp_SOFT_HEAP_LIMIT: {
|
| + sqlite3_int64 N;
|
| + if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
|
| + sqlite3_soft_heap_limit64(N);
|
| + }
|
| + returnSingleInt(v, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + ** PRAGMA threads
|
| + ** PRAGMA threads = N
|
| + **
|
| + ** Configure the maximum number of worker threads. Return the new
|
| + ** maximum, which might be less than requested.
|
| + */
|
| + case PragTyp_THREADS: {
|
| + sqlite3_int64 N;
|
| + if( zRight
|
| + && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK
|
| + && N>=0
|
| + ){
|
| + sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
|
| + }
|
| + returnSingleInt(v, "threads",
|
| + sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
|
| + break;
|
| + }
|
| +
|
| +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
| + /*
|
| + ** Report the current state of file logs for all databases
|
| + */
|
| + case PragTyp_LOCK_STATUS: {
|
| + static const char *const azLockName[] = {
|
| + "unlocked", "shared", "reserved", "pending", "exclusive"
|
| + };
|
| + static const char *azCol[] = { "database", "status" };
|
| + int i;
|
| + setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
|
| + pParse->nMem = 2;
|
| + for(i=0; i<db->nDb; i++){
|
| + Btree *pBt;
|
| + const char *zState = "unknown";
|
| + int j;
|
| + if( db->aDb[i].zName==0 ) continue;
|
| + pBt = db->aDb[i].pBt;
|
| + if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
|
| + zState = "closed";
|
| + }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0,
|
| + SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
|
| + zState = azLockName[j];
|
| + }
|
| + sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState);
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
|
| + }
|
| + break;
|
| + }
|
| +#endif
|
| +
|
| +#ifdef SQLITE_HAS_CODEC
|
| + case PragTyp_KEY: {
|
| + if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
|
| + break;
|
| + }
|
| + case PragTyp_REKEY: {
|
| + if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
|
| + break;
|
| + }
|
| + case PragTyp_HEXKEY: {
|
| + if( zRight ){
|
| + u8 iByte;
|
| + int i;
|
| + char zKey[40];
|
| + for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zRight[i]); i++){
|
| + iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
|
| + if( (i&1)!=0 ) zKey[i/2] = iByte;
|
| + }
|
| + if( (zLeft[3] & 0xf)==0xb ){
|
| + sqlite3_key_v2(db, zDb, zKey, i/2);
|
| + }else{
|
| + sqlite3_rekey_v2(db, zDb, zKey, i/2);
|
| + }
|
| + }
|
| + break;
|
| + }
|
| +#endif
|
| +#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
|
| + case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){
|
| +#ifdef SQLITE_HAS_CODEC
|
| + if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
|
| + sqlite3_activate_see(&zRight[4]);
|
| + }
|
| +#endif
|
| +#ifdef SQLITE_ENABLE_CEROD
|
| + if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
|
| + sqlite3_activate_cerod(&zRight[6]);
|
| + }
|
| +#endif
|
| + }
|
| + break;
|
| +#endif
|
| +
|
| + } /* End of the PRAGMA switch */
|
| +
|
| +pragma_out:
|
| + sqlite3DbFree(db, zLeft);
|
| + sqlite3DbFree(db, zRight);
|
| +}
|
| +
|
| +#endif /* SQLITE_OMIT_PRAGMA */
|
| +
|
| +/************** End of pragma.c **********************************************/
|
| +/************** Begin file prepare.c *****************************************/
|
| +/*
|
| +** 2005 May 25
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains the implementation of the sqlite3_prepare()
|
| +** interface, and routines that contribute to loading the database schema
|
| +** from disk.
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +/*
|
| +** Fill the InitData structure with an error message that indicates
|
| +** that the database is corrupt.
|
| +*/
|
| +static void corruptSchema(
|
| + InitData *pData, /* Initialization context */
|
| + const char *zObj, /* Object being parsed at the point of error */
|
| + const char *zExtra /* Error information */
|
| +){
|
| + sqlite3 *db = pData->db;
|
| + if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
|
| + char *z;
|
| + if( zObj==0 ) zObj = "?";
|
| + z = sqlite3_mprintf("malformed database schema (%s)", zObj);
|
| + if( z && zExtra ) z = sqlite3_mprintf("%z - %s", z, zExtra);
|
| + sqlite3DbFree(db, *pData->pzErrMsg);
|
| + *pData->pzErrMsg = z;
|
| + if( z==0 ) db->mallocFailed = 1;
|
| + }
|
| + pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT;
|
| +}
|
| +
|
| +/*
|
| +** This is the callback routine for the code that initializes the
|
| +** database. See sqlite3Init() below for additional information.
|
| +** This routine is also called from the OP_ParseSchema opcode of the VDBE.
|
| +**
|
| +** Each callback contains the following information:
|
| +**
|
| +** argv[0] = name of thing being created
|
| +** argv[1] = root page number for table or index. 0 for trigger or view.
|
| +** argv[2] = SQL text for the CREATE statement.
|
| +**
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
| + InitData *pData = (InitData*)pInit;
|
| + sqlite3 *db = pData->db;
|
| + int iDb = pData->iDb;
|
| +
|
| + assert( argc==3 );
|
| + UNUSED_PARAMETER2(NotUsed, argc);
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + DbClearProperty(db, iDb, DB_Empty);
|
| + if( db->mallocFailed ){
|
| + corruptSchema(pData, argv[0], 0);
|
| + return 1;
|
| + }
|
| +
|
| + assert( iDb>=0 && iDb<db->nDb );
|
| + if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
| + if( argv[1]==0 ){
|
| + corruptSchema(pData, argv[0], 0);
|
| + }else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){
|
| + /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
| + ** But because db->init.busy is set to 1, no VDBE code is generated
|
| + ** or executed. All the parser does is build the internal data
|
| + ** structures that describe the table, index, or view.
|
| + */
|
| + int rc;
|
| + sqlite3_stmt *pStmt;
|
| + TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
|
| +
|
| + assert( db->init.busy );
|
| + db->init.iDb = iDb;
|
| + db->init.newTnum = sqlite3Atoi(argv[1]);
|
| + db->init.orphanTrigger = 0;
|
| + TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
|
| + rc = db->errCode;
|
| + assert( (rc&0xFF)==(rcp&0xFF) );
|
| + db->init.iDb = 0;
|
| + if( SQLITE_OK!=rc ){
|
| + if( db->init.orphanTrigger ){
|
| + assert( iDb==1 );
|
| + }else{
|
| + pData->rc = rc;
|
| + if( rc==SQLITE_NOMEM ){
|
| + db->mallocFailed = 1;
|
| + }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
|
| + corruptSchema(pData, argv[0], sqlite3_errmsg(db));
|
| + }
|
| + }
|
| + }
|
| + sqlite3_finalize(pStmt);
|
| + }else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){
|
| + corruptSchema(pData, argv[0], 0);
|
| + }else{
|
| + /* If the SQL column is blank it means this is an index that
|
| + ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
|
| + ** constraint for a CREATE TABLE. The index should have already
|
| + ** been created when we processed the CREATE TABLE. All we have
|
| + ** to do here is record the root page number for that index.
|
| + */
|
| + Index *pIndex;
|
| + pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
|
| + if( pIndex==0 ){
|
| + /* This can occur if there exists an index on a TEMP table which
|
| + ** has the same name as another index on a permanent index. Since
|
| + ** the permanent table is hidden by the TEMP table, we can also
|
| + ** safely ignore the index on the permanent table.
|
| + */
|
| + /* Do Nothing */;
|
| + }else if( sqlite3GetInt32(argv[1], &pIndex->tnum)==0 ){
|
| + corruptSchema(pData, argv[0], "invalid rootpage");
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** Attempt to read the database schema and initialize internal
|
| +** data structures for a single database file. The index of the
|
| +** database file is given by iDb. iDb==0 is used for the main
|
| +** database. iDb==1 should never be used. iDb>=2 is used for
|
| +** auxiliary databases. Return one of the SQLITE_ error codes to
|
| +** indicate success or failure.
|
| +*/
|
| +static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
| + int rc;
|
| + int i;
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| + int size;
|
| +#endif
|
| + Table *pTab;
|
| + Db *pDb;
|
| + char const *azArg[4];
|
| + int meta[5];
|
| + InitData initData;
|
| + char const *zMasterSchema;
|
| + char const *zMasterName;
|
| + int openedTransaction = 0;
|
| +
|
| + /*
|
| + ** The master database table has a structure like this
|
| + */
|
| + static const char master_schema[] =
|
| + "CREATE TABLE sqlite_master(\n"
|
| + " type text,\n"
|
| + " name text,\n"
|
| + " tbl_name text,\n"
|
| + " rootpage integer,\n"
|
| + " sql text\n"
|
| + ")"
|
| + ;
|
| +#ifndef SQLITE_OMIT_TEMPDB
|
| + static const char temp_master_schema[] =
|
| + "CREATE TEMP TABLE sqlite_temp_master(\n"
|
| + " type text,\n"
|
| + " name text,\n"
|
| + " tbl_name text,\n"
|
| + " rootpage integer,\n"
|
| + " sql text\n"
|
| + ")"
|
| + ;
|
| +#else
|
| + #define temp_master_schema 0
|
| +#endif
|
| +
|
| + assert( iDb>=0 && iDb<db->nDb );
|
| + assert( db->aDb[iDb].pSchema );
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
|
| +
|
| + /* zMasterSchema and zInitScript are set to point at the master schema
|
| + ** and initialisation script appropriate for the database being
|
| + ** initialized. zMasterName is the name of the master table.
|
| + */
|
| + if( !OMIT_TEMPDB && iDb==1 ){
|
| + zMasterSchema = temp_master_schema;
|
| + }else{
|
| + zMasterSchema = master_schema;
|
| + }
|
| + zMasterName = SCHEMA_TABLE(iDb);
|
| +
|
| + /* Construct the schema tables. */
|
| + azArg[0] = zMasterName;
|
| + azArg[1] = "1";
|
| + azArg[2] = zMasterSchema;
|
| + azArg[3] = 0;
|
| + initData.db = db;
|
| + initData.iDb = iDb;
|
| + initData.rc = SQLITE_OK;
|
| + initData.pzErrMsg = pzErrMsg;
|
| + sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
|
| + if( initData.rc ){
|
| + rc = initData.rc;
|
| + goto error_out;
|
| + }
|
| + pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
|
| + if( ALWAYS(pTab) ){
|
| + pTab->tabFlags |= TF_Readonly;
|
| + }
|
| +
|
| + /* Create a cursor to hold the database open
|
| + */
|
| + pDb = &db->aDb[iDb];
|
| + if( pDb->pBt==0 ){
|
| + if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
|
| + DbSetProperty(db, 1, DB_SchemaLoaded);
|
| + }
|
| + return SQLITE_OK;
|
| + }
|
| +
|
| + /* If there is not already a read-only (or read-write) transaction opened
|
| + ** on the b-tree database, open one now. If a transaction is opened, it
|
| + ** will be closed before this function returns. */
|
| + sqlite3BtreeEnter(pDb->pBt);
|
| + if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){
|
| + rc = sqlite3BtreeBeginTrans(pDb->pBt, 0);
|
| + if( rc!=SQLITE_OK ){
|
| + sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc));
|
| + goto initone_error_out;
|
| + }
|
| + openedTransaction = 1;
|
| + }
|
| +
|
| + /* Get the database meta information.
|
| + **
|
| + ** Meta values are as follows:
|
| + ** meta[0] Schema cookie. Changes with each schema change.
|
| + ** meta[1] File format of schema layer.
|
| + ** meta[2] Size of the page cache.
|
| + ** meta[3] Largest rootpage (auto/incr_vacuum mode)
|
| + ** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE
|
| + ** meta[5] User version
|
| + ** meta[6] Incremental vacuum mode
|
| + ** meta[7] unused
|
| + ** meta[8] unused
|
| + ** meta[9] unused
|
| + **
|
| + ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to
|
| + ** the possible values of meta[4].
|
| + */
|
| + for(i=0; i<ArraySize(meta); i++){
|
| + sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
|
| + }
|
| + pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1];
|
| +
|
| + /* If opening a non-empty database, check the text encoding. For the
|
| + ** main database, set sqlite3.enc to the encoding of the main database.
|
| + ** For an attached db, it is an error if the encoding is not the same
|
| + ** as sqlite3.enc.
|
| + */
|
| + if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
|
| + if( iDb==0 ){
|
| +#ifndef SQLITE_OMIT_UTF16
|
| + u8 encoding;
|
| + /* If opening the main database, set ENC(db). */
|
| + encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
|
| + if( encoding==0 ) encoding = SQLITE_UTF8;
|
| + ENC(db) = encoding;
|
| +#else
|
| + ENC(db) = SQLITE_UTF8;
|
| +#endif
|
| + }else{
|
| + /* If opening an attached database, the encoding much match ENC(db) */
|
| + if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
|
| + sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
|
| + " text encoding as main database");
|
| + rc = SQLITE_ERROR;
|
| + goto initone_error_out;
|
| + }
|
| + }
|
| + }else{
|
| + DbSetProperty(db, iDb, DB_Empty);
|
| + }
|
| + pDb->pSchema->enc = ENC(db);
|
| +
|
| + if( pDb->pSchema->cache_size==0 ){
|
| +#ifndef SQLITE_OMIT_DEPRECATED
|
| + size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]);
|
| + if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
|
| + pDb->pSchema->cache_size = size;
|
| +#else
|
| + pDb->pSchema->cache_size = SQLITE_DEFAULT_CACHE_SIZE;
|
| +#endif
|
| + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
| + }
|
| +
|
| + /*
|
| + ** file_format==1 Version 3.0.0.
|
| + ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN
|
| + ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults
|
| + ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants
|
| + */
|
| + pDb->pSchema->file_format = (u8)meta[BTREE_FILE_FORMAT-1];
|
| + if( pDb->pSchema->file_format==0 ){
|
| + pDb->pSchema->file_format = 1;
|
| + }
|
| + if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
|
| + sqlite3SetString(pzErrMsg, db, "unsupported file format");
|
| + rc = SQLITE_ERROR;
|
| + goto initone_error_out;
|
| + }
|
| +
|
| + /* Ticket #2804: When we open a database in the newer file format,
|
| + ** clear the legacy_file_format pragma flag so that a VACUUM will
|
| + ** not downgrade the database and thus invalidate any descending
|
| + ** indices that the user might have created.
|
| + */
|
| + if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){
|
| + db->flags &= ~SQLITE_LegacyFileFmt;
|
| + }
|
| +
|
| + /* Read the schema information out of the schema tables
|
| + */
|
| + assert( db->init.busy );
|
| + {
|
| + char *zSql;
|
| + zSql = sqlite3MPrintf(db,
|
| + "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
|
| + db->aDb[iDb].zName, zMasterName);
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + {
|
| + sqlite3_xauth xAuth;
|
| + xAuth = db->xAuth;
|
| + db->xAuth = 0;
|
| +#endif
|
| + rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
|
| +#ifndef SQLITE_OMIT_AUTHORIZATION
|
| + db->xAuth = xAuth;
|
| + }
|
| +#endif
|
| + if( rc==SQLITE_OK ) rc = initData.rc;
|
| + sqlite3DbFree(db, zSql);
|
| +#ifndef SQLITE_OMIT_ANALYZE
|
| + if( rc==SQLITE_OK ){
|
| + sqlite3AnalysisLoad(db, iDb);
|
| + }
|
| +#endif
|
| + }
|
| + if( db->mallocFailed ){
|
| + rc = SQLITE_NOMEM;
|
| + sqlite3ResetAllSchemasOfConnection(db);
|
| + }
|
| + if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
|
| + /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
|
| + ** the schema loaded, even if errors occurred. In this situation the
|
| + ** current sqlite3_prepare() operation will fail, but the following one
|
| + ** will attempt to compile the supplied statement against whatever subset
|
| + ** of the schema was loaded before the error occurred. The primary
|
| + ** purpose of this is to allow access to the sqlite_master table
|
| + ** even when its contents have been corrupted.
|
| + */
|
| + DbSetProperty(db, iDb, DB_SchemaLoaded);
|
| + rc = SQLITE_OK;
|
| + }
|
| +
|
| + /* Jump here for an error that occurs after successfully allocating
|
| + ** curMain and calling sqlite3BtreeEnter(). For an error that occurs
|
| + ** before that point, jump to error_out.
|
| + */
|
| +initone_error_out:
|
| + if( openedTransaction ){
|
| + sqlite3BtreeCommit(pDb->pBt);
|
| + }
|
| + sqlite3BtreeLeave(pDb->pBt);
|
| +
|
| +error_out:
|
| + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
| + db->mallocFailed = 1;
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Initialize all database files - the main database file, the file
|
| +** used to store temporary tables, and any additional database files
|
| +** created using ATTACH statements. Return a success code. If an
|
| +** error occurs, write an error message into *pzErrMsg.
|
| +**
|
| +** After a database is initialized, the DB_SchemaLoaded bit is set
|
| +** bit is set in the flags field of the Db structure. If the database
|
| +** file was of zero-length, then the DB_Empty flag is also set.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
| + int i, rc;
|
| + int commit_internal = !(db->flags&SQLITE_InternChanges);
|
| +
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
|
| + assert( db->init.busy==0 );
|
| + rc = SQLITE_OK;
|
| + db->init.busy = 1;
|
| + ENC(db) = SCHEMA_ENC(db);
|
| + for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
| + if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
|
| + rc = sqlite3InitOne(db, i, pzErrMsg);
|
| + if( rc ){
|
| + sqlite3ResetOneSchema(db, i);
|
| + }
|
| + }
|
| +
|
| + /* Once all the other databases have been initialized, load the schema
|
| + ** for the TEMP database. This is loaded last, as the TEMP database
|
| + ** schema may contain references to objects in other databases.
|
| + */
|
| +#ifndef SQLITE_OMIT_TEMPDB
|
| + assert( db->nDb>1 );
|
| + if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
|
| + rc = sqlite3InitOne(db, 1, pzErrMsg);
|
| + if( rc ){
|
| + sqlite3ResetOneSchema(db, 1);
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + db->init.busy = 0;
|
| + if( rc==SQLITE_OK && commit_internal ){
|
| + sqlite3CommitInternalChanges(db);
|
| + }
|
| +
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** This routine is a no-op if the database schema is already initialized.
|
| +** Otherwise, the schema is loaded. An error code is returned.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){
|
| + int rc = SQLITE_OK;
|
| + sqlite3 *db = pParse->db;
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + if( !db->init.busy ){
|
| + rc = sqlite3Init(db, &pParse->zErrMsg);
|
| + }
|
| + if( rc!=SQLITE_OK ){
|
| + pParse->rc = rc;
|
| + pParse->nErr++;
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Check schema cookies in all databases. If any cookie is out
|
| +** of date set pParse->rc to SQLITE_SCHEMA. If all schema cookies
|
| +** make no changes to pParse->rc.
|
| +*/
|
| +static void schemaIsValid(Parse *pParse){
|
| + sqlite3 *db = pParse->db;
|
| + int iDb;
|
| + int rc;
|
| + int cookie;
|
| +
|
| + assert( pParse->checkSchema );
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + for(iDb=0; iDb<db->nDb; iDb++){
|
| + int openedTransaction = 0; /* True if a transaction is opened */
|
| + Btree *pBt = db->aDb[iDb].pBt; /* Btree database to read cookie from */
|
| + if( pBt==0 ) continue;
|
| +
|
| + /* If there is not already a read-only (or read-write) transaction opened
|
| + ** on the b-tree database, open one now. If a transaction is opened, it
|
| + ** will be closed immediately after reading the meta-value. */
|
| + if( !sqlite3BtreeIsInReadTrans(pBt) ){
|
| + rc = sqlite3BtreeBeginTrans(pBt, 0);
|
| + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
| + db->mallocFailed = 1;
|
| + }
|
| + if( rc!=SQLITE_OK ) return;
|
| + openedTransaction = 1;
|
| + }
|
| +
|
| + /* Read the schema cookie from the database. If it does not match the
|
| + ** value stored as part of the in-memory schema representation,
|
| + ** set Parse.rc to SQLITE_SCHEMA. */
|
| + sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
| + sqlite3ResetOneSchema(db, iDb);
|
| + pParse->rc = SQLITE_SCHEMA;
|
| + }
|
| +
|
| + /* Close the transaction, if one was opened. */
|
| + if( openedTransaction ){
|
| + sqlite3BtreeCommit(pBt);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Convert a schema pointer into the iDb index that indicates
|
| +** which database file in db->aDb[] the schema refers to.
|
| +**
|
| +** If the same database is attached more than once, the first
|
| +** attached database is returned.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
| + int i = -1000000;
|
| +
|
| + /* If pSchema is NULL, then return -1000000. This happens when code in
|
| + ** expr.c is trying to resolve a reference to a transient table (i.e. one
|
| + ** created by a sub-select). In this case the return value of this
|
| + ** function should never be used.
|
| + **
|
| + ** We return -1000000 instead of the more usual -1 simply because using
|
| + ** -1000000 as the incorrect index into db->aDb[] is much
|
| + ** more likely to cause a segfault than -1 (of course there are assert()
|
| + ** statements too, but it never hurts to play the odds).
|
| + */
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + if( pSchema ){
|
| + for(i=0; ALWAYS(i<db->nDb); i++){
|
| + if( db->aDb[i].pSchema==pSchema ){
|
| + break;
|
| + }
|
| + }
|
| + assert( i>=0 && i<db->nDb );
|
| + }
|
| + return i;
|
| +}
|
| +
|
| +/*
|
| +** Free all memory allocations in the pParse object
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){
|
| + if( pParse ){
|
| + sqlite3 *db = pParse->db;
|
| + sqlite3DbFree(db, pParse->aLabel);
|
| + sqlite3ExprListDelete(db, pParse->pConstExpr);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
| +*/
|
| +static int sqlite3Prepare(
|
| + sqlite3 *db, /* Database handle. */
|
| + const char *zSql, /* UTF-8 encoded SQL statement. */
|
| + int nBytes, /* Length of zSql in bytes. */
|
| + int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
|
| + Vdbe *pReprepare, /* VM being reprepared */
|
| + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
| + const char **pzTail /* OUT: End of parsed string */
|
| +){
|
| + Parse *pParse; /* Parsing context */
|
| + char *zErrMsg = 0; /* Error message */
|
| + int rc = SQLITE_OK; /* Result code */
|
| + int i; /* Loop counter */
|
| +
|
| + /* Allocate the parsing context */
|
| + pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
|
| + if( pParse==0 ){
|
| + rc = SQLITE_NOMEM;
|
| + goto end_prepare;
|
| + }
|
| + pParse->pReprepare = pReprepare;
|
| + assert( ppStmt && *ppStmt==0 );
|
| + assert( !db->mallocFailed );
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| +
|
| + /* Check to verify that it is possible to get a read lock on all
|
| + ** database schemas. The inability to get a read lock indicates that
|
| + ** some other database connection is holding a write-lock, which in
|
| + ** turn means that the other connection has made uncommitted changes
|
| + ** to the schema.
|
| + **
|
| + ** Were we to proceed and prepare the statement against the uncommitted
|
| + ** schema changes and if those schema changes are subsequently rolled
|
| + ** back and different changes are made in their place, then when this
|
| + ** prepared statement goes to run the schema cookie would fail to detect
|
| + ** the schema change. Disaster would follow.
|
| + **
|
| + ** This thread is currently holding mutexes on all Btrees (because
|
| + ** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it
|
| + ** is not possible for another thread to start a new schema change
|
| + ** while this routine is running. Hence, we do not need to hold
|
| + ** locks on the schema, we just need to make sure nobody else is
|
| + ** holding them.
|
| + **
|
| + ** Note that setting READ_UNCOMMITTED overrides most lock detection,
|
| + ** but it does *not* override schema lock detection, so this all still
|
| + ** works even if READ_UNCOMMITTED is set.
|
| + */
|
| + for(i=0; i<db->nDb; i++) {
|
| + Btree *pBt = db->aDb[i].pBt;
|
| + if( pBt ){
|
| + assert( sqlite3BtreeHoldsMutex(pBt) );
|
| + rc = sqlite3BtreeSchemaLocked(pBt);
|
| + if( rc ){
|
| + const char *zDb = db->aDb[i].zName;
|
| + sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
|
| + testcase( db->flags & SQLITE_ReadUncommitted );
|
| + goto end_prepare;
|
| + }
|
| + }
|
| + }
|
| +
|
| + sqlite3VtabUnlockList(db);
|
| +
|
| + pParse->db = db;
|
| + pParse->nQueryLoop = 0; /* Logarithmic, so 0 really means 1 */
|
| + if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
|
| + char *zSqlCopy;
|
| + int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
|
| + testcase( nBytes==mxLen );
|
| + testcase( nBytes==mxLen+1 );
|
| + if( nBytes>mxLen ){
|
| + sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long");
|
| + rc = sqlite3ApiExit(db, SQLITE_TOOBIG);
|
| + goto end_prepare;
|
| + }
|
| + zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
|
| + if( zSqlCopy ){
|
| + sqlite3RunParser(pParse, zSqlCopy, &zErrMsg);
|
| + sqlite3DbFree(db, zSqlCopy);
|
| + pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
|
| + }else{
|
| + pParse->zTail = &zSql[nBytes];
|
| + }
|
| + }else{
|
| + sqlite3RunParser(pParse, zSql, &zErrMsg);
|
| + }
|
| + assert( 0==pParse->nQueryLoop );
|
| +
|
| + if( db->mallocFailed ){
|
| + pParse->rc = SQLITE_NOMEM;
|
| + }
|
| + if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
|
| + if( pParse->checkSchema ){
|
| + schemaIsValid(pParse);
|
| + }
|
| + if( db->mallocFailed ){
|
| + pParse->rc = SQLITE_NOMEM;
|
| + }
|
| + if( pzTail ){
|
| + *pzTail = pParse->zTail;
|
| + }
|
| + rc = pParse->rc;
|
| +
|
| +#ifndef SQLITE_OMIT_EXPLAIN
|
| + if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
|
| + static const char * const azColName[] = {
|
| + "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
|
| + "selectid", "order", "from", "detail"
|
| + };
|
| + int iFirst, mx;
|
| + if( pParse->explain==2 ){
|
| + sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
|
| + iFirst = 8;
|
| + mx = 12;
|
| + }else{
|
| + sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
|
| + iFirst = 0;
|
| + mx = 8;
|
| + }
|
| + for(i=iFirst; i<mx; i++){
|
| + sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME,
|
| + azColName[i], SQLITE_STATIC);
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + if( db->init.busy==0 ){
|
| + Vdbe *pVdbe = pParse->pVdbe;
|
| + sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
|
| + }
|
| + if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
|
| + sqlite3VdbeFinalize(pParse->pVdbe);
|
| + assert(!(*ppStmt));
|
| + }else{
|
| + *ppStmt = (sqlite3_stmt*)pParse->pVdbe;
|
| + }
|
| +
|
| + if( zErrMsg ){
|
| + sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg);
|
| + sqlite3DbFree(db, zErrMsg);
|
| + }else{
|
| + sqlite3Error(db, rc);
|
| + }
|
| +
|
| + /* Delete any TriggerPrg structures allocated while parsing this statement. */
|
| + while( pParse->pTriggerPrg ){
|
| + TriggerPrg *pT = pParse->pTriggerPrg;
|
| + pParse->pTriggerPrg = pT->pNext;
|
| + sqlite3DbFree(db, pT);
|
| + }
|
| +
|
| +end_prepare:
|
| +
|
| + sqlite3ParserReset(pParse);
|
| + sqlite3StackFree(db, pParse);
|
| + rc = sqlite3ApiExit(db, rc);
|
| + assert( (rc&db->errMask)==rc );
|
| + return rc;
|
| +}
|
| +static int sqlite3LockAndPrepare(
|
| + sqlite3 *db, /* Database handle. */
|
| + const char *zSql, /* UTF-8 encoded SQL statement. */
|
| + int nBytes, /* Length of zSql in bytes. */
|
| + int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
|
| + Vdbe *pOld, /* VM being reprepared */
|
| + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
| + const char **pzTail /* OUT: End of parsed string */
|
| +){
|
| + int rc;
|
| +
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
|
| +#endif
|
| + *ppStmt = 0;
|
| + if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
|
| + return SQLITE_MISUSE_BKPT;
|
| + }
|
| + sqlite3_mutex_enter(db->mutex);
|
| + sqlite3BtreeEnterAll(db);
|
| + rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
|
| + if( rc==SQLITE_SCHEMA ){
|
| + sqlite3_finalize(*ppStmt);
|
| + rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
|
| + }
|
| + sqlite3BtreeLeaveAll(db);
|
| + sqlite3_mutex_leave(db->mutex);
|
| + assert( rc==SQLITE_OK || *ppStmt==0 );
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Rerun the compilation of a statement after a schema change.
|
| +**
|
| +** If the statement is successfully recompiled, return SQLITE_OK. Otherwise,
|
| +** if the statement cannot be recompiled because another connection has
|
| +** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error
|
| +** occurs, return SQLITE_SCHEMA.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
|
| + int rc;
|
| + sqlite3_stmt *pNew;
|
| + const char *zSql;
|
| + sqlite3 *db;
|
| +
|
| + assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) );
|
| + zSql = sqlite3_sql((sqlite3_stmt *)p);
|
| + assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */
|
| + db = sqlite3VdbeDb(p);
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0);
|
| + if( rc ){
|
| + if( rc==SQLITE_NOMEM ){
|
| + db->mallocFailed = 1;
|
| + }
|
| + assert( pNew==0 );
|
| + return rc;
|
| + }else{
|
| + assert( pNew!=0 );
|
| + }
|
| + sqlite3VdbeSwap((Vdbe*)pNew, p);
|
| + sqlite3TransferBindings(pNew, (sqlite3_stmt*)p);
|
| + sqlite3VdbeResetStepResult((Vdbe*)pNew);
|
| + sqlite3VdbeFinalize((Vdbe*)pNew);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Two versions of the official API. Legacy and new use. In the legacy
|
| +** version, the original SQL text is not saved in the prepared statement
|
| +** and so if a schema change occurs, SQLITE_SCHEMA is returned by
|
| +** sqlite3_step(). In the new version, the original SQL text is retained
|
| +** and the statement is automatically recompiled if an schema change
|
| +** occurs.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
|
| + sqlite3 *db, /* Database handle. */
|
| + const char *zSql, /* UTF-8 encoded SQL statement. */
|
| + int nBytes, /* Length of zSql in bytes. */
|
| + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
| + const char **pzTail /* OUT: End of parsed string */
|
| +){
|
| + int rc;
|
| + rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail);
|
| + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
| + return rc;
|
| +}
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
|
| + sqlite3 *db, /* Database handle. */
|
| + const char *zSql, /* UTF-8 encoded SQL statement. */
|
| + int nBytes, /* Length of zSql in bytes. */
|
| + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
| + const char **pzTail /* OUT: End of parsed string */
|
| +){
|
| + int rc;
|
| + rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail);
|
| + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
| + return rc;
|
| +}
|
| +
|
| +
|
| +#ifndef SQLITE_OMIT_UTF16
|
| +/*
|
| +** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
|
| +*/
|
| +static int sqlite3Prepare16(
|
| + sqlite3 *db, /* Database handle. */
|
| + const void *zSql, /* UTF-16 encoded SQL statement. */
|
| + int nBytes, /* Length of zSql in bytes. */
|
| + int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
|
| + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
| + const void **pzTail /* OUT: End of parsed string */
|
| +){
|
| + /* This function currently works by first transforming the UTF-16
|
| + ** encoded string to UTF-8, then invoking sqlite3_prepare(). The
|
| + ** tricky bit is figuring out the pointer to return in *pzTail.
|
| + */
|
| + char *zSql8;
|
| + const char *zTail8 = 0;
|
| + int rc = SQLITE_OK;
|
| +
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
|
| +#endif
|
| + *ppStmt = 0;
|
| + if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
|
| + return SQLITE_MISUSE_BKPT;
|
| + }
|
| + if( nBytes>=0 ){
|
| + int sz;
|
| + const char *z = (const char*)zSql;
|
| + for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
|
| + nBytes = sz;
|
| + }
|
| + sqlite3_mutex_enter(db->mutex);
|
| + zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
|
| + if( zSql8 ){
|
| + rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
|
| + }
|
| +
|
| + if( zTail8 && pzTail ){
|
| + /* If sqlite3_prepare returns a tail pointer, we calculate the
|
| + ** equivalent pointer into the UTF-16 string by counting the unicode
|
| + ** characters between zSql8 and zTail8, and then returning a pointer
|
| + ** the same number of characters into the UTF-16 string.
|
| + */
|
| + int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
|
| + *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
|
| + }
|
| + sqlite3DbFree(db, zSql8);
|
| + rc = sqlite3ApiExit(db, rc);
|
| + sqlite3_mutex_leave(db->mutex);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Two versions of the official API. Legacy and new use. In the legacy
|
| +** version, the original SQL text is not saved in the prepared statement
|
| +** and so if a schema change occurs, SQLITE_SCHEMA is returned by
|
| +** sqlite3_step(). In the new version, the original SQL text is retained
|
| +** and the statement is automatically recompiled if an schema change
|
| +** occurs.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
|
| + sqlite3 *db, /* Database handle. */
|
| + const void *zSql, /* UTF-16 encoded SQL statement. */
|
| + int nBytes, /* Length of zSql in bytes. */
|
| + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
| + const void **pzTail /* OUT: End of parsed string */
|
| +){
|
| + int rc;
|
| + rc = sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail);
|
| + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
| + return rc;
|
| +}
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
|
| + sqlite3 *db, /* Database handle. */
|
| + const void *zSql, /* UTF-16 encoded SQL statement. */
|
| + int nBytes, /* Length of zSql in bytes. */
|
| + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
| + const void **pzTail /* OUT: End of parsed string */
|
| +){
|
| + int rc;
|
| + rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
|
| + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
| + return rc;
|
| +}
|
| +
|
| +#endif /* SQLITE_OMIT_UTF16 */
|
| +
|
| +/************** End of prepare.c *********************************************/
|
| +/************** Begin file select.c ******************************************/
|
| +/*
|
| +** 2001 September 15
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains C code routines that are called by the parser
|
| +** to handle SELECT statements in SQLite.
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +
|
| +/*
|
| +** Trace output macros
|
| +*/
|
| +#if SELECTTRACE_ENABLED
|
| +/***/ int sqlite3SelectTrace = 0;
|
| +# define SELECTTRACE(K,P,S,X) \
|
| + if(sqlite3SelectTrace&(K)) \
|
| + sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\
|
| + (S)->zSelName,(S)),\
|
| + sqlite3DebugPrintf X
|
| +#else
|
| +# define SELECTTRACE(K,P,S,X)
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** An instance of the following object is used to record information about
|
| +** how to process the DISTINCT keyword, to simplify passing that information
|
| +** into the selectInnerLoop() routine.
|
| +*/
|
| +typedef struct DistinctCtx DistinctCtx;
|
| +struct DistinctCtx {
|
| + u8 isTnct; /* True if the DISTINCT keyword is present */
|
| + u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
|
| + int tabTnct; /* Ephemeral table used for DISTINCT processing */
|
| + int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
|
| +};
|
| +
|
| +/*
|
| +** An instance of the following object is used to record information about
|
| +** the ORDER BY (or GROUP BY) clause of query is being coded.
|
| +*/
|
| +typedef struct SortCtx SortCtx;
|
| +struct SortCtx {
|
| + ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */
|
| + int nOBSat; /* Number of ORDER BY terms satisfied by indices */
|
| + int iECursor; /* Cursor number for the sorter */
|
| + int regReturn; /* Register holding block-output return address */
|
| + int labelBkOut; /* Start label for the block-output subroutine */
|
| + int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
|
| + int labelDone; /* Jump here when done, ex: LIMIT reached */
|
| + u8 sortFlags; /* Zero or more SORTFLAG_* bits */
|
| +};
|
| +#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
|
| +
|
| +/*
|
| +** Delete all the content of a Select structure. Deallocate the structure
|
| +** itself only if bFree is true.
|
| +*/
|
| +static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
| + while( p ){
|
| + Select *pPrior = p->pPrior;
|
| + sqlite3ExprListDelete(db, p->pEList);
|
| + sqlite3SrcListDelete(db, p->pSrc);
|
| + sqlite3ExprDelete(db, p->pWhere);
|
| + sqlite3ExprListDelete(db, p->pGroupBy);
|
| + sqlite3ExprDelete(db, p->pHaving);
|
| + sqlite3ExprListDelete(db, p->pOrderBy);
|
| + sqlite3ExprDelete(db, p->pLimit);
|
| + sqlite3ExprDelete(db, p->pOffset);
|
| + sqlite3WithDelete(db, p->pWith);
|
| + if( bFree ) sqlite3DbFree(db, p);
|
| + p = pPrior;
|
| + bFree = 1;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Initialize a SelectDest structure.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
|
| + pDest->eDest = (u8)eDest;
|
| + pDest->iSDParm = iParm;
|
| + pDest->affSdst = 0;
|
| + pDest->iSdst = 0;
|
| + pDest->nSdst = 0;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Allocate a new Select structure and return a pointer to that
|
| +** structure.
|
| +*/
|
| +SQLITE_PRIVATE Select *sqlite3SelectNew(
|
| + Parse *pParse, /* Parsing context */
|
| + ExprList *pEList, /* which columns to include in the result */
|
| + SrcList *pSrc, /* the FROM clause -- which tables to scan */
|
| + Expr *pWhere, /* the WHERE clause */
|
| + ExprList *pGroupBy, /* the GROUP BY clause */
|
| + Expr *pHaving, /* the HAVING clause */
|
| + ExprList *pOrderBy, /* the ORDER BY clause */
|
| + u16 selFlags, /* Flag parameters, such as SF_Distinct */
|
| + Expr *pLimit, /* LIMIT value. NULL means not used */
|
| + Expr *pOffset /* OFFSET value. NULL means no offset */
|
| +){
|
| + Select *pNew;
|
| + Select standin;
|
| + sqlite3 *db = pParse->db;
|
| + pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
|
| + if( pNew==0 ){
|
| + assert( db->mallocFailed );
|
| + pNew = &standin;
|
| + memset(pNew, 0, sizeof(*pNew));
|
| + }
|
| + if( pEList==0 ){
|
| + pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
|
| + }
|
| + pNew->pEList = pEList;
|
| + if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
|
| + pNew->pSrc = pSrc;
|
| + pNew->pWhere = pWhere;
|
| + pNew->pGroupBy = pGroupBy;
|
| + pNew->pHaving = pHaving;
|
| + pNew->pOrderBy = pOrderBy;
|
| + pNew->selFlags = selFlags;
|
| + pNew->op = TK_SELECT;
|
| + pNew->pLimit = pLimit;
|
| + pNew->pOffset = pOffset;
|
| + assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
|
| + pNew->addrOpenEphm[0] = -1;
|
| + pNew->addrOpenEphm[1] = -1;
|
| + if( db->mallocFailed ) {
|
| + clearSelect(db, pNew, pNew!=&standin);
|
| + pNew = 0;
|
| + }else{
|
| + assert( pNew->pSrc!=0 || pParse->nErr>0 );
|
| + }
|
| + assert( pNew!=&standin );
|
| + return pNew;
|
| +}
|
| +
|
| +#if SELECTTRACE_ENABLED
|
| +/*
|
| +** Set the name of a Select object
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
|
| + if( p && zName ){
|
| + sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName);
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** Delete the given Select structure and all of its substructures.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
|
| + clearSelect(db, p, 1);
|
| +}
|
| +
|
| +/*
|
| +** Return a pointer to the right-most SELECT statement in a compound.
|
| +*/
|
| +static Select *findRightmost(Select *p){
|
| + while( p->pNext ) p = p->pNext;
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** Given 1 to 3 identifiers preceding the JOIN keyword, determine the
|
| +** type of join. Return an integer constant that expresses that type
|
| +** in terms of the following bit values:
|
| +**
|
| +** JT_INNER
|
| +** JT_CROSS
|
| +** JT_OUTER
|
| +** JT_NATURAL
|
| +** JT_LEFT
|
| +** JT_RIGHT
|
| +**
|
| +** A full outer join is the combination of JT_LEFT and JT_RIGHT.
|
| +**
|
| +** If an illegal or unsupported join type is seen, then still return
|
| +** a join type, but put an error in the pParse structure.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
|
| + int jointype = 0;
|
| + Token *apAll[3];
|
| + Token *p;
|
| + /* 0123456789 123456789 123456789 123 */
|
| + static const char zKeyText[] = "naturaleftouterightfullinnercross";
|
| + static const struct {
|
| + u8 i; /* Beginning of keyword text in zKeyText[] */
|
| + u8 nChar; /* Length of the keyword in characters */
|
| + u8 code; /* Join type mask */
|
| + } aKeyword[] = {
|
| + /* natural */ { 0, 7, JT_NATURAL },
|
| + /* left */ { 6, 4, JT_LEFT|JT_OUTER },
|
| + /* outer */ { 10, 5, JT_OUTER },
|
| + /* right */ { 14, 5, JT_RIGHT|JT_OUTER },
|
| + /* full */ { 19, 4, JT_LEFT|JT_RIGHT|JT_OUTER },
|
| + /* inner */ { 23, 5, JT_INNER },
|
| + /* cross */ { 28, 5, JT_INNER|JT_CROSS },
|
| + };
|
| + int i, j;
|
| + apAll[0] = pA;
|
| + apAll[1] = pB;
|
| + apAll[2] = pC;
|
| + for(i=0; i<3 && apAll[i]; i++){
|
| + p = apAll[i];
|
| + for(j=0; j<ArraySize(aKeyword); j++){
|
| + if( p->n==aKeyword[j].nChar
|
| + && sqlite3StrNICmp((char*)p->z, &zKeyText[aKeyword[j].i], p->n)==0 ){
|
| + jointype |= aKeyword[j].code;
|
| + break;
|
| + }
|
| + }
|
| + testcase( j==0 || j==1 || j==2 || j==3 || j==4 || j==5 || j==6 );
|
| + if( j>=ArraySize(aKeyword) ){
|
| + jointype |= JT_ERROR;
|
| + break;
|
| + }
|
| + }
|
| + if(
|
| + (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) ||
|
| + (jointype & JT_ERROR)!=0
|
| + ){
|
| + const char *zSp = " ";
|
| + assert( pB!=0 );
|
| + if( pC==0 ){ zSp++; }
|
| + sqlite3ErrorMsg(pParse, "unknown or unsupported join type: "
|
| + "%T %T%s%T", pA, pB, zSp, pC);
|
| + jointype = JT_INNER;
|
| + }else if( (jointype & JT_OUTER)!=0
|
| + && (jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "RIGHT and FULL OUTER JOINs are not currently supported");
|
| + jointype = JT_INNER;
|
| + }
|
| + return jointype;
|
| +}
|
| +
|
| +/*
|
| +** Return the index of a column in a table. Return -1 if the column
|
| +** is not contained in the table.
|
| +*/
|
| +static int columnIndex(Table *pTab, const char *zCol){
|
| + int i;
|
| + for(i=0; i<pTab->nCol; i++){
|
| + if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| +/*
|
| +** Search the first N tables in pSrc, from left to right, looking for a
|
| +** table that has a column named zCol.
|
| +**
|
| +** When found, set *piTab and *piCol to the table index and column index
|
| +** of the matching column and return TRUE.
|
| +**
|
| +** If not found, return FALSE.
|
| +*/
|
| +static int tableAndColumnIndex(
|
| + SrcList *pSrc, /* Array of tables to search */
|
| + int N, /* Number of tables in pSrc->a[] to search */
|
| + const char *zCol, /* Name of the column we are looking for */
|
| + int *piTab, /* Write index of pSrc->a[] here */
|
| + int *piCol /* Write index of pSrc->a[*piTab].pTab->aCol[] here */
|
| +){
|
| + int i; /* For looping over tables in pSrc */
|
| + int iCol; /* Index of column matching zCol */
|
| +
|
| + assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
|
| + for(i=0; i<N; i++){
|
| + iCol = columnIndex(pSrc->a[i].pTab, zCol);
|
| + if( iCol>=0 ){
|
| + if( piTab ){
|
| + *piTab = i;
|
| + *piCol = iCol;
|
| + }
|
| + return 1;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** This function is used to add terms implied by JOIN syntax to the
|
| +** WHERE clause expression of a SELECT statement. The new term, which
|
| +** is ANDed with the existing WHERE clause, is of the form:
|
| +**
|
| +** (tab1.col1 = tab2.col2)
|
| +**
|
| +** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the
|
| +** (iSrc+1)'th. Column col1 is column iColLeft of tab1, and col2 is
|
| +** column iColRight of tab2.
|
| +*/
|
| +static void addWhereTerm(
|
| + Parse *pParse, /* Parsing context */
|
| + SrcList *pSrc, /* List of tables in FROM clause */
|
| + int iLeft, /* Index of first table to join in pSrc */
|
| + int iColLeft, /* Index of column in first table */
|
| + int iRight, /* Index of second table in pSrc */
|
| + int iColRight, /* Index of column in second table */
|
| + int isOuterJoin, /* True if this is an OUTER join */
|
| + Expr **ppWhere /* IN/OUT: The WHERE clause to add to */
|
| +){
|
| + sqlite3 *db = pParse->db;
|
| + Expr *pE1;
|
| + Expr *pE2;
|
| + Expr *pEq;
|
| +
|
| + assert( iLeft<iRight );
|
| + assert( pSrc->nSrc>iRight );
|
| + assert( pSrc->a[iLeft].pTab );
|
| + assert( pSrc->a[iRight].pTab );
|
| +
|
| + pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
|
| + pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
|
| +
|
| + pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
|
| + if( pEq && isOuterJoin ){
|
| + ExprSetProperty(pEq, EP_FromJoin);
|
| + assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
|
| + ExprSetVVAProperty(pEq, EP_NoReduce);
|
| + pEq->iRightJoinTable = (i16)pE2->iTable;
|
| + }
|
| + *ppWhere = sqlite3ExprAnd(db, *ppWhere, pEq);
|
| +}
|
| +
|
| +/*
|
| +** Set the EP_FromJoin property on all terms of the given expression.
|
| +** And set the Expr.iRightJoinTable to iTable for every term in the
|
| +** expression.
|
| +**
|
| +** The EP_FromJoin property is used on terms of an expression to tell
|
| +** the LEFT OUTER JOIN processing logic that this term is part of the
|
| +** join restriction specified in the ON or USING clause and not a part
|
| +** of the more general WHERE clause. These terms are moved over to the
|
| +** WHERE clause during join processing but we need to remember that they
|
| +** originated in the ON or USING clause.
|
| +**
|
| +** The Expr.iRightJoinTable tells the WHERE clause processing that the
|
| +** expression depends on table iRightJoinTable even if that table is not
|
| +** explicitly mentioned in the expression. That information is needed
|
| +** for cases like this:
|
| +**
|
| +** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5
|
| +**
|
| +** The where clause needs to defer the handling of the t1.x=5
|
| +** term until after the t2 loop of the join. In that way, a
|
| +** NULL t2 row will be inserted whenever t1.x!=5. If we do not
|
| +** defer the handling of t1.x=5, it will be processed immediately
|
| +** after the t1 loop and rows with t1.x!=5 will never appear in
|
| +** the output, which is incorrect.
|
| +*/
|
| +static void setJoinExpr(Expr *p, int iTable){
|
| + while( p ){
|
| + ExprSetProperty(p, EP_FromJoin);
|
| + assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
| + ExprSetVVAProperty(p, EP_NoReduce);
|
| + p->iRightJoinTable = (i16)iTable;
|
| + if( p->op==TK_FUNCTION && p->x.pList ){
|
| + int i;
|
| + for(i=0; i<p->x.pList->nExpr; i++){
|
| + setJoinExpr(p->x.pList->a[i].pExpr, iTable);
|
| + }
|
| + }
|
| + setJoinExpr(p->pLeft, iTable);
|
| + p = p->pRight;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This routine processes the join information for a SELECT statement.
|
| +** ON and USING clauses are converted into extra terms of the WHERE clause.
|
| +** NATURAL joins also create extra WHERE clause terms.
|
| +**
|
| +** The terms of a FROM clause are contained in the Select.pSrc structure.
|
| +** The left most table is the first entry in Select.pSrc. The right-most
|
| +** table is the last entry. The join operator is held in the entry to
|
| +** the left. Thus entry 0 contains the join operator for the join between
|
| +** entries 0 and 1. Any ON or USING clauses associated with the join are
|
| +** also attached to the left entry.
|
| +**
|
| +** This routine returns the number of errors encountered.
|
| +*/
|
| +static int sqliteProcessJoin(Parse *pParse, Select *p){
|
| + SrcList *pSrc; /* All tables in the FROM clause */
|
| + int i, j; /* Loop counters */
|
| + struct SrcList_item *pLeft; /* Left table being joined */
|
| + struct SrcList_item *pRight; /* Right table being joined */
|
| +
|
| + pSrc = p->pSrc;
|
| + pLeft = &pSrc->a[0];
|
| + pRight = &pLeft[1];
|
| + for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
|
| + Table *pLeftTab = pLeft->pTab;
|
| + Table *pRightTab = pRight->pTab;
|
| + int isOuter;
|
| +
|
| + if( NEVER(pLeftTab==0 || pRightTab==0) ) continue;
|
| + isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
|
| +
|
| + /* When the NATURAL keyword is present, add WHERE clause terms for
|
| + ** every column that the two tables have in common.
|
| + */
|
| + if( pRight->fg.jointype & JT_NATURAL ){
|
| + if( pRight->pOn || pRight->pUsing ){
|
| + sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
|
| + "an ON or USING clause", 0);
|
| + return 1;
|
| + }
|
| + for(j=0; j<pRightTab->nCol; j++){
|
| + char *zName; /* Name of column in the right table */
|
| + int iLeft; /* Matching left table */
|
| + int iLeftCol; /* Matching column in the left table */
|
| +
|
| + zName = pRightTab->aCol[j].zName;
|
| + if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){
|
| + addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j,
|
| + isOuter, &p->pWhere);
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Disallow both ON and USING clauses in the same join
|
| + */
|
| + if( pRight->pOn && pRight->pUsing ){
|
| + sqlite3ErrorMsg(pParse, "cannot have both ON and USING "
|
| + "clauses in the same join");
|
| + return 1;
|
| + }
|
| +
|
| + /* Add the ON clause to the end of the WHERE clause, connected by
|
| + ** an AND operator.
|
| + */
|
| + if( pRight->pOn ){
|
| + if( isOuter ) setJoinExpr(pRight->pOn, pRight->iCursor);
|
| + p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn);
|
| + pRight->pOn = 0;
|
| + }
|
| +
|
| + /* Create extra terms on the WHERE clause for each column named
|
| + ** in the USING clause. Example: If the two tables to be joined are
|
| + ** A and B and the USING clause names X, Y, and Z, then add this
|
| + ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
|
| + ** Report an error if any column mentioned in the USING clause is
|
| + ** not contained in both tables to be joined.
|
| + */
|
| + if( pRight->pUsing ){
|
| + IdList *pList = pRight->pUsing;
|
| + for(j=0; j<pList->nId; j++){
|
| + char *zName; /* Name of the term in the USING clause */
|
| + int iLeft; /* Table on the left with matching column name */
|
| + int iLeftCol; /* Column number of matching column on the left */
|
| + int iRightCol; /* Column number of matching column on the right */
|
| +
|
| + zName = pList->a[j].zName;
|
| + iRightCol = columnIndex(pRightTab, zName);
|
| + if( iRightCol<0
|
| + || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol)
|
| + ){
|
| + sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
|
| + "not present in both tables", zName);
|
| + return 1;
|
| + }
|
| + addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol,
|
| + isOuter, &p->pWhere);
|
| + }
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/* Forward reference */
|
| +static KeyInfo *keyInfoFromExprList(
|
| + Parse *pParse, /* Parsing context */
|
| + ExprList *pList, /* Form the KeyInfo object from this ExprList */
|
| + int iStart, /* Begin with this column of pList */
|
| + int nExtra /* Add this many extra columns to the end */
|
| +);
|
| +
|
| +/*
|
| +** Generate code that will push the record in registers regData
|
| +** through regData+nData-1 onto the sorter.
|
| +*/
|
| +static void pushOntoSorter(
|
| + Parse *pParse, /* Parser context */
|
| + SortCtx *pSort, /* Information about the ORDER BY clause */
|
| + Select *pSelect, /* The whole SELECT statement */
|
| + int regData, /* First register holding data to be sorted */
|
| + int regOrigData, /* First register holding data before packing */
|
| + int nData, /* Number of elements in the data array */
|
| + int nPrefixReg /* No. of reg prior to regData available for use */
|
| +){
|
| + Vdbe *v = pParse->pVdbe; /* Stmt under construction */
|
| + int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0);
|
| + int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */
|
| + int nBase = nExpr + bSeq + nData; /* Fields in sorter record */
|
| + int regBase; /* Regs for sorter record */
|
| + int regRecord = ++pParse->nMem; /* Assembled sorter record */
|
| + int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
|
| + int op; /* Opcode to add sorter record to sorter */
|
| + int iLimit; /* LIMIT counter */
|
| +
|
| + assert( bSeq==0 || bSeq==1 );
|
| + assert( nData==1 || regData==regOrigData );
|
| + if( nPrefixReg ){
|
| + assert( nPrefixReg==nExpr+bSeq );
|
| + regBase = regData - nExpr - bSeq;
|
| + }else{
|
| + regBase = pParse->nMem + 1;
|
| + pParse->nMem += nBase;
|
| + }
|
| + assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
|
| + iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
|
| + pSort->labelDone = sqlite3VdbeMakeLabel(v);
|
| + sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
|
| + SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
|
| + if( bSeq ){
|
| + sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
|
| + }
|
| + if( nPrefixReg==0 ){
|
| + sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
|
| + if( nOBSat>0 ){
|
| + int regPrevKey; /* The first nOBSat columns of the previous row */
|
| + int addrFirst; /* Address of the OP_IfNot opcode */
|
| + int addrJmp; /* Address of the OP_Jump opcode */
|
| + VdbeOp *pOp; /* Opcode that opens the sorter */
|
| + int nKey; /* Number of sorting key columns, including OP_Sequence */
|
| + KeyInfo *pKI; /* Original KeyInfo on the sorter table */
|
| +
|
| + regPrevKey = pParse->nMem+1;
|
| + pParse->nMem += pSort->nOBSat;
|
| + nKey = nExpr - pSort->nOBSat + bSeq;
|
| + if( bSeq ){
|
| + addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr);
|
| + }else{
|
| + addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor);
|
| + }
|
| + VdbeCoverage(v);
|
| + sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat);
|
| + pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
|
| + if( pParse->db->mallocFailed ) return;
|
| + pOp->p2 = nKey + nData;
|
| + pKI = pOp->p4.pKeyInfo;
|
| + memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
|
| + sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
|
| + testcase( pKI->nXField>2 );
|
| + pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
|
| + pKI->nXField-1);
|
| + addrJmp = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
|
| + pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
|
| + pSort->regReturn = ++pParse->nMem;
|
| + sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
| + sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
|
| + if( iLimit ){
|
| + sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone);
|
| + VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeJumpHere(v, addrFirst);
|
| + sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
|
| + sqlite3VdbeJumpHere(v, addrJmp);
|
| + }
|
| + if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
| + op = OP_SorterInsert;
|
| + }else{
|
| + op = OP_IdxInsert;
|
| + }
|
| + sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
|
| + if( iLimit ){
|
| + int addr;
|
| + addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
|
| + sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
|
| + sqlite3VdbeJumpHere(v, addr);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Add code to implement the OFFSET
|
| +*/
|
| +static void codeOffset(
|
| + Vdbe *v, /* Generate code into this VM */
|
| + int iOffset, /* Register holding the offset counter */
|
| + int iContinue /* Jump here to skip the current record */
|
| +){
|
| + if( iOffset>0 ){
|
| + sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v);
|
| + VdbeComment((v, "OFFSET"));
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Add code that will check to make sure the N registers starting at iMem
|
| +** form a distinct entry. iTab is a sorting index that holds previously
|
| +** seen combinations of the N values. A new entry is made in iTab
|
| +** if the current N values are new.
|
| +**
|
| +** A jump to addrRepeat is made and the N+1 values are popped from the
|
| +** stack if the top N elements are not distinct.
|
| +*/
|
| +static void codeDistinct(
|
| + Parse *pParse, /* Parsing and code generating context */
|
| + int iTab, /* A sorting index used to test for distinctness */
|
| + int addrRepeat, /* Jump to here if not distinct */
|
| + int N, /* Number of elements */
|
| + int iMem /* First element */
|
| +){
|
| + Vdbe *v;
|
| + int r1;
|
| +
|
| + v = pParse->pVdbe;
|
| + r1 = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| +/*
|
| +** Generate an error message when a SELECT is used within a subexpression
|
| +** (example: "a IN (SELECT * FROM table)") but it has more than 1 result
|
| +** column. We do this in a subroutine because the error used to occur
|
| +** in multiple places. (The error only occurs in one place now, but we
|
| +** retain the subroutine to minimize code disruption.)
|
| +*/
|
| +static int checkForMultiColumnSelectError(
|
| + Parse *pParse, /* Parse context. */
|
| + SelectDest *pDest, /* Destination of SELECT results */
|
| + int nExpr /* Number of result columns returned by SELECT */
|
| +){
|
| + int eDest = pDest->eDest;
|
| + if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){
|
| + sqlite3ErrorMsg(pParse, "only a single result allowed for "
|
| + "a SELECT that is part of an expression");
|
| + return 1;
|
| + }else{
|
| + return 0;
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| +** This routine generates the code for the inside of the inner loop
|
| +** of a SELECT.
|
| +**
|
| +** If srcTab is negative, then the pEList expressions
|
| +** are evaluated in order to get the data for this row. If srcTab is
|
| +** zero or more, then data is pulled from srcTab and pEList is used only
|
| +** to get number columns and the datatype for each column.
|
| +*/
|
| +static void selectInnerLoop(
|
| + Parse *pParse, /* The parser context */
|
| + Select *p, /* The complete select statement being coded */
|
| + ExprList *pEList, /* List of values being extracted */
|
| + int srcTab, /* Pull data from this table */
|
| + SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
|
| + DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
|
| + SelectDest *pDest, /* How to dispose of the results */
|
| + int iContinue, /* Jump here to continue with next row */
|
| + int iBreak /* Jump here to break out of the inner loop */
|
| +){
|
| + Vdbe *v = pParse->pVdbe;
|
| + int i;
|
| + int hasDistinct; /* True if the DISTINCT keyword is present */
|
| + int regResult; /* Start of memory holding result set */
|
| + int eDest = pDest->eDest; /* How to dispose of results */
|
| + int iParm = pDest->iSDParm; /* First argument to disposal method */
|
| + int nResultCol; /* Number of result columns */
|
| + int nPrefixReg = 0; /* Number of extra registers before regResult */
|
| +
|
| + assert( v );
|
| + assert( pEList!=0 );
|
| + hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
|
| + if( pSort && pSort->pOrderBy==0 ) pSort = 0;
|
| + if( pSort==0 && !hasDistinct ){
|
| + assert( iContinue!=0 );
|
| + codeOffset(v, p->iOffset, iContinue);
|
| + }
|
| +
|
| + /* Pull the requested columns.
|
| + */
|
| + nResultCol = pEList->nExpr;
|
| +
|
| + if( pDest->iSdst==0 ){
|
| + if( pSort ){
|
| + nPrefixReg = pSort->pOrderBy->nExpr;
|
| + if( !(pSort->sortFlags & SORTFLAG_UseSorter) ) nPrefixReg++;
|
| + pParse->nMem += nPrefixReg;
|
| + }
|
| + pDest->iSdst = pParse->nMem+1;
|
| + pParse->nMem += nResultCol;
|
| + }else if( pDest->iSdst+nResultCol > pParse->nMem ){
|
| + /* This is an error condition that can result, for example, when a SELECT
|
| + ** on the right-hand side of an INSERT contains more result columns than
|
| + ** there are columns in the table on the left. The error will be caught
|
| + ** and reported later. But we need to make sure enough memory is allocated
|
| + ** to avoid other spurious errors in the meantime. */
|
| + pParse->nMem += nResultCol;
|
| + }
|
| + pDest->nSdst = nResultCol;
|
| + regResult = pDest->iSdst;
|
| + if( srcTab>=0 ){
|
| + for(i=0; i<nResultCol; i++){
|
| + sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
|
| + VdbeComment((v, "%s", pEList->a[i].zName));
|
| + }
|
| + }else if( eDest!=SRT_Exists ){
|
| + /* If the destination is an EXISTS(...) expression, the actual
|
| + ** values returned by the SELECT are not required.
|
| + */
|
| + u8 ecelFlags;
|
| + if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){
|
| + ecelFlags = SQLITE_ECEL_DUP;
|
| + }else{
|
| + ecelFlags = 0;
|
| + }
|
| + sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
|
| + }
|
| +
|
| + /* If the DISTINCT keyword was present on the SELECT statement
|
| + ** and this row has been seen before, then do not make this row
|
| + ** part of the result.
|
| + */
|
| + if( hasDistinct ){
|
| + switch( pDistinct->eTnctType ){
|
| + case WHERE_DISTINCT_ORDERED: {
|
| + VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
|
| + int iJump; /* Jump destination */
|
| + int regPrev; /* Previous row content */
|
| +
|
| + /* Allocate space for the previous row */
|
| + regPrev = pParse->nMem+1;
|
| + pParse->nMem += nResultCol;
|
| +
|
| + /* Change the OP_OpenEphemeral coded earlier to an OP_Null
|
| + ** sets the MEM_Cleared bit on the first register of the
|
| + ** previous value. This will cause the OP_Ne below to always
|
| + ** fail on the first iteration of the loop even if the first
|
| + ** row is all NULLs.
|
| + */
|
| + sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
|
| + pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct);
|
| + pOp->opcode = OP_Null;
|
| + pOp->p1 = 1;
|
| + pOp->p2 = regPrev;
|
| +
|
| + iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
|
| + for(i=0; i<nResultCol; i++){
|
| + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
|
| + if( i<nResultCol-1 ){
|
| + sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
|
| + VdbeCoverage(v);
|
| + }else{
|
| + sqlite3VdbeAddOp3(v, OP_Eq, regResult+i, iContinue, regPrev+i);
|
| + VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
|
| + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
| + }
|
| + assert( sqlite3VdbeCurrentAddr(v)==iJump || pParse->db->mallocFailed );
|
| + sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1);
|
| + break;
|
| + }
|
| +
|
| + case WHERE_DISTINCT_UNIQUE: {
|
| + sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
|
| + break;
|
| + }
|
| +
|
| + default: {
|
| + assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
|
| + codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol,
|
| + regResult);
|
| + break;
|
| + }
|
| + }
|
| + if( pSort==0 ){
|
| + codeOffset(v, p->iOffset, iContinue);
|
| + }
|
| + }
|
| +
|
| + switch( eDest ){
|
| + /* In this mode, write each query result to the key of the temporary
|
| + ** table iParm.
|
| + */
|
| +#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
| + case SRT_Union: {
|
| + int r1;
|
| + r1 = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| + break;
|
| + }
|
| +
|
| + /* Construct a record from the query result, but instead of
|
| + ** saving that record, use it as a key to delete elements from
|
| + ** the temporary table iParm.
|
| + */
|
| + case SRT_Except: {
|
| + sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nResultCol);
|
| + break;
|
| + }
|
| +#endif /* SQLITE_OMIT_COMPOUND_SELECT */
|
| +
|
| + /* Store the result as data using a unique key.
|
| + */
|
| + case SRT_Fifo:
|
| + case SRT_DistFifo:
|
| + case SRT_Table:
|
| + case SRT_EphemTab: {
|
| + int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1);
|
| + testcase( eDest==SRT_Table );
|
| + testcase( eDest==SRT_EphemTab );
|
| + testcase( eDest==SRT_Fifo );
|
| + testcase( eDest==SRT_DistFifo );
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
|
| +#ifndef SQLITE_OMIT_CTE
|
| + if( eDest==SRT_DistFifo ){
|
| + /* If the destination is DistFifo, then cursor (iParm+1) is open
|
| + ** on an ephemeral index. If the current row is already present
|
| + ** in the index, do not write it to the output. If not, add the
|
| + ** current row to the index and proceed with writing it to the
|
| + ** output table as well. */
|
| + int addr = sqlite3VdbeCurrentAddr(v) + 4;
|
| + sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0);
|
| + VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
|
| + assert( pSort==0 );
|
| + }
|
| +#endif
|
| + if( pSort ){
|
| + pushOntoSorter(pParse, pSort, p, r1+nPrefixReg,regResult,1,nPrefixReg);
|
| + }else{
|
| + int r2 = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| + sqlite3ReleaseTempReg(pParse, r2);
|
| + }
|
| + sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1);
|
| + break;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| + /* If we are creating a set for an "expr IN (SELECT ...)" construct,
|
| + ** then there should be a single item on the stack. Write this
|
| + ** item into the set table with bogus data.
|
| + */
|
| + case SRT_Set: {
|
| + assert( nResultCol==1 );
|
| + pDest->affSdst =
|
| + sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
|
| + if( pSort ){
|
| + /* At first glance you would think we could optimize out the
|
| + ** ORDER BY in this case since the order of entries in the set
|
| + ** does not matter. But there might be a LIMIT clause, in which
|
| + ** case the order does matter */
|
| + pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
|
| + }else{
|
| + int r1 = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
|
| + sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + /* If any row exist in the result set, record that fact and abort.
|
| + */
|
| + case SRT_Exists: {
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm);
|
| + /* The LIMIT clause will terminate the loop for us */
|
| + break;
|
| + }
|
| +
|
| + /* If this is a scalar select that is part of an expression, then
|
| + ** store the results in the appropriate memory cell and break out
|
| + ** of the scan loop.
|
| + */
|
| + case SRT_Mem: {
|
| + assert( nResultCol==1 );
|
| + if( pSort ){
|
| + pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
|
| + }else{
|
| + assert( regResult==iParm );
|
| + /* The LIMIT clause will jump out of the loop for us */
|
| + }
|
| + break;
|
| + }
|
| +#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
|
| +
|
| + case SRT_Coroutine: /* Send data to a co-routine */
|
| + case SRT_Output: { /* Return the results */
|
| + testcase( eDest==SRT_Coroutine );
|
| + testcase( eDest==SRT_Output );
|
| + if( pSort ){
|
| + pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
|
| + nPrefixReg);
|
| + }else if( eDest==SRT_Coroutine ){
|
| + sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
|
| + }else{
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol);
|
| + sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
|
| + }
|
| + break;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_CTE
|
| + /* Write the results into a priority queue that is order according to
|
| + ** pDest->pOrderBy (in pSO). pDest->iSDParm (in iParm) is the cursor for an
|
| + ** index with pSO->nExpr+2 columns. Build a key using pSO for the first
|
| + ** pSO->nExpr columns, then make sure all keys are unique by adding a
|
| + ** final OP_Sequence column. The last column is the record as a blob.
|
| + */
|
| + case SRT_DistQueue:
|
| + case SRT_Queue: {
|
| + int nKey;
|
| + int r1, r2, r3;
|
| + int addrTest = 0;
|
| + ExprList *pSO;
|
| + pSO = pDest->pOrderBy;
|
| + assert( pSO );
|
| + nKey = pSO->nExpr;
|
| + r1 = sqlite3GetTempReg(pParse);
|
| + r2 = sqlite3GetTempRange(pParse, nKey+2);
|
| + r3 = r2+nKey+1;
|
| + if( eDest==SRT_DistQueue ){
|
| + /* If the destination is DistQueue, then cursor (iParm+1) is open
|
| + ** on a second ephemeral index that holds all values every previously
|
| + ** added to the queue. */
|
| + addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0,
|
| + regResult, nResultCol);
|
| + VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r3);
|
| + if( eDest==SRT_DistQueue ){
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
| + }
|
| + for(i=0; i<nKey; i++){
|
| + sqlite3VdbeAddOp2(v, OP_SCopy,
|
| + regResult + pSO->a[i].u.x.iOrderByCol - 1,
|
| + r2+i);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
| + if( addrTest ) sqlite3VdbeJumpHere(v, addrTest);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| + sqlite3ReleaseTempRange(pParse, r2, nKey+2);
|
| + break;
|
| + }
|
| +#endif /* SQLITE_OMIT_CTE */
|
| +
|
| +
|
| +
|
| +#if !defined(SQLITE_OMIT_TRIGGER)
|
| + /* Discard the results. This is used for SELECT statements inside
|
| + ** the body of a TRIGGER. The purpose of such selects is to call
|
| + ** user-defined functions that have side effects. We do not care
|
| + ** about the actual results of the select.
|
| + */
|
| + default: {
|
| + assert( eDest==SRT_Discard );
|
| + break;
|
| + }
|
| +#endif
|
| + }
|
| +
|
| + /* Jump to the end of the loop if the LIMIT is reached. Except, if
|
| + ** there is a sorter, in which case the sorter has already limited
|
| + ** the output for us.
|
| + */
|
| + if( pSort==0 && p->iLimit ){
|
| + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Allocate a KeyInfo object sufficient for an index of N key columns and
|
| +** X extra columns.
|
| +*/
|
| +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
| + KeyInfo *p = sqlite3DbMallocZero(0,
|
| + sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1));
|
| + if( p ){
|
| + p->aSortOrder = (u8*)&p->aColl[N+X];
|
| + p->nField = (u16)N;
|
| + p->nXField = (u16)X;
|
| + p->enc = ENC(db);
|
| + p->db = db;
|
| + p->nRef = 1;
|
| + }else{
|
| + db->mallocFailed = 1;
|
| + }
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** Deallocate a KeyInfo object
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
|
| + if( p ){
|
| + assert( p->nRef>0 );
|
| + p->nRef--;
|
| + if( p->nRef==0 ) sqlite3DbFree(0, p);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Make a new pointer to a KeyInfo object
|
| +*/
|
| +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo *p){
|
| + if( p ){
|
| + assert( p->nRef>0 );
|
| + p->nRef++;
|
| + }
|
| + return p;
|
| +}
|
| +
|
| +#ifdef SQLITE_DEBUG
|
| +/*
|
| +** Return TRUE if a KeyInfo object can be change. The KeyInfo object
|
| +** can only be changed if this is just a single reference to the object.
|
| +**
|
| +** This routine is used only inside of assert() statements.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
|
| +#endif /* SQLITE_DEBUG */
|
| +
|
| +/*
|
| +** Given an expression list, generate a KeyInfo structure that records
|
| +** the collating sequence for each expression in that expression list.
|
| +**
|
| +** If the ExprList is an ORDER BY or GROUP BY clause then the resulting
|
| +** KeyInfo structure is appropriate for initializing a virtual index to
|
| +** implement that clause. If the ExprList is the result set of a SELECT
|
| +** then the KeyInfo structure is appropriate for initializing a virtual
|
| +** index to implement a DISTINCT test.
|
| +**
|
| +** Space to hold the KeyInfo structure is obtained from malloc. The calling
|
| +** function is responsible for seeing that this structure is eventually
|
| +** freed.
|
| +*/
|
| +static KeyInfo *keyInfoFromExprList(
|
| + Parse *pParse, /* Parsing context */
|
| + ExprList *pList, /* Form the KeyInfo object from this ExprList */
|
| + int iStart, /* Begin with this column of pList */
|
| + int nExtra /* Add this many extra columns to the end */
|
| +){
|
| + int nExpr;
|
| + KeyInfo *pInfo;
|
| + struct ExprList_item *pItem;
|
| + sqlite3 *db = pParse->db;
|
| + int i;
|
| +
|
| + nExpr = pList->nExpr;
|
| + pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1);
|
| + if( pInfo ){
|
| + assert( sqlite3KeyInfoIsWriteable(pInfo) );
|
| + for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
|
| + CollSeq *pColl;
|
| + pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
| + if( !pColl ) pColl = db->pDfltColl;
|
| + pInfo->aColl[i-iStart] = pColl;
|
| + pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
|
| + }
|
| + }
|
| + return pInfo;
|
| +}
|
| +
|
| +/*
|
| +** Name of the connection operator, used for error messages.
|
| +*/
|
| +static const char *selectOpName(int id){
|
| + char *z;
|
| + switch( id ){
|
| + case TK_ALL: z = "UNION ALL"; break;
|
| + case TK_INTERSECT: z = "INTERSECT"; break;
|
| + case TK_EXCEPT: z = "EXCEPT"; break;
|
| + default: z = "UNION"; break;
|
| + }
|
| + return z;
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_EXPLAIN
|
| +/*
|
| +** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
|
| +** is a no-op. Otherwise, it adds a single row of output to the EQP result,
|
| +** where the caption is of the form:
|
| +**
|
| +** "USE TEMP B-TREE FOR xxx"
|
| +**
|
| +** where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which
|
| +** is determined by the zUsage argument.
|
| +*/
|
| +static void explainTempTable(Parse *pParse, const char *zUsage){
|
| + if( pParse->explain==2 ){
|
| + Vdbe *v = pParse->pVdbe;
|
| + char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage);
|
| + sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Assign expression b to lvalue a. A second, no-op, version of this macro
|
| +** is provided when SQLITE_OMIT_EXPLAIN is defined. This allows the code
|
| +** in sqlite3Select() to assign values to structure member variables that
|
| +** only exist if SQLITE_OMIT_EXPLAIN is not defined without polluting the
|
| +** code with #ifndef directives.
|
| +*/
|
| +# define explainSetInteger(a, b) a = b
|
| +
|
| +#else
|
| +/* No-op versions of the explainXXX() functions and macros. */
|
| +# define explainTempTable(y,z)
|
| +# define explainSetInteger(y,z)
|
| +#endif
|
| +
|
| +#if !defined(SQLITE_OMIT_EXPLAIN) && !defined(SQLITE_OMIT_COMPOUND_SELECT)
|
| +/*
|
| +** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
|
| +** is a no-op. Otherwise, it adds a single row of output to the EQP result,
|
| +** where the caption is of one of the two forms:
|
| +**
|
| +** "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)"
|
| +** "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)"
|
| +**
|
| +** where iSub1 and iSub2 are the integers passed as the corresponding
|
| +** function parameters, and op is the text representation of the parameter
|
| +** of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT,
|
| +** TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is
|
| +** false, or the second form if it is true.
|
| +*/
|
| +static void explainComposite(
|
| + Parse *pParse, /* Parse context */
|
| + int op, /* One of TK_UNION, TK_EXCEPT etc. */
|
| + int iSub1, /* Subquery id 1 */
|
| + int iSub2, /* Subquery id 2 */
|
| + int bUseTmp /* True if a temp table was used */
|
| +){
|
| + assert( op==TK_UNION || op==TK_EXCEPT || op==TK_INTERSECT || op==TK_ALL );
|
| + if( pParse->explain==2 ){
|
| + Vdbe *v = pParse->pVdbe;
|
| + char *zMsg = sqlite3MPrintf(
|
| + pParse->db, "COMPOUND SUBQUERIES %d AND %d %s(%s)", iSub1, iSub2,
|
| + bUseTmp?"USING TEMP B-TREE ":"", selectOpName(op)
|
| + );
|
| + sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
|
| + }
|
| +}
|
| +#else
|
| +/* No-op versions of the explainXXX() functions and macros. */
|
| +# define explainComposite(v,w,x,y,z)
|
| +#endif
|
| +
|
| +/*
|
| +** If the inner loop was generated using a non-null pOrderBy argument,
|
| +** then the results were placed in a sorter. After the loop is terminated
|
| +** we need to run the sorter and output the results. The following
|
| +** routine generates the code needed to do that.
|
| +*/
|
| +static void generateSortTail(
|
| + Parse *pParse, /* Parsing context */
|
| + Select *p, /* The SELECT statement */
|
| + SortCtx *pSort, /* Information on the ORDER BY clause */
|
| + int nColumn, /* Number of columns of data */
|
| + SelectDest *pDest /* Write the sorted results here */
|
| +){
|
| + Vdbe *v = pParse->pVdbe; /* The prepared statement */
|
| + int addrBreak = pSort->labelDone; /* Jump here to exit loop */
|
| + int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
|
| + int addr;
|
| + int addrOnce = 0;
|
| + int iTab;
|
| + ExprList *pOrderBy = pSort->pOrderBy;
|
| + int eDest = pDest->eDest;
|
| + int iParm = pDest->iSDParm;
|
| + int regRow;
|
| + int regRowid;
|
| + int nKey;
|
| + int iSortTab; /* Sorter cursor to read from */
|
| + int nSortData; /* Trailing values to read from sorter */
|
| + int i;
|
| + int bSeq; /* True if sorter record includes seq. no. */
|
| +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
| + struct ExprList_item *aOutEx = p->pEList->a;
|
| +#endif
|
| +
|
| + assert( addrBreak<0 );
|
| + if( pSort->labelBkOut ){
|
| + sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
| + sqlite3VdbeGoto(v, addrBreak);
|
| + sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
|
| + }
|
| + iTab = pSort->iECursor;
|
| + if( eDest==SRT_Output || eDest==SRT_Coroutine ){
|
| + regRowid = 0;
|
| + regRow = pDest->iSdst;
|
| + nSortData = nColumn;
|
| + }else{
|
| + regRowid = sqlite3GetTempReg(pParse);
|
| + regRow = sqlite3GetTempReg(pParse);
|
| + nSortData = 1;
|
| + }
|
| + nKey = pOrderBy->nExpr - pSort->nOBSat;
|
| + if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
| + int regSortOut = ++pParse->nMem;
|
| + iSortTab = pParse->nTab++;
|
| + if( pSort->labelBkOut ){
|
| + addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
|
| + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
|
| + addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
|
| + VdbeCoverage(v);
|
| + codeOffset(v, p->iOffset, addrContinue);
|
| + sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
|
| + bSeq = 0;
|
| + }else{
|
| + addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
|
| + codeOffset(v, p->iOffset, addrContinue);
|
| + iSortTab = iTab;
|
| + bSeq = 1;
|
| + }
|
| + for(i=0; i<nSortData; i++){
|
| + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
|
| + VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
|
| + }
|
| + switch( eDest ){
|
| + case SRT_EphemTab: {
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| + break;
|
| + }
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| + case SRT_Set: {
|
| + assert( nColumn==1 );
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid,
|
| + &pDest->affSdst, 1);
|
| + sqlite3ExprCacheAffinityChange(pParse, regRow, 1);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
|
| + break;
|
| + }
|
| + case SRT_Mem: {
|
| + assert( nColumn==1 );
|
| + sqlite3ExprCodeMove(pParse, regRow, iParm, 1);
|
| + /* The LIMIT clause will terminate the loop for us */
|
| + break;
|
| + }
|
| +#endif
|
| + default: {
|
| + assert( eDest==SRT_Output || eDest==SRT_Coroutine );
|
| + testcase( eDest==SRT_Output );
|
| + testcase( eDest==SRT_Coroutine );
|
| + if( eDest==SRT_Output ){
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn);
|
| + sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn);
|
| + }else{
|
| + sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + if( regRowid ){
|
| + sqlite3ReleaseTempReg(pParse, regRow);
|
| + sqlite3ReleaseTempReg(pParse, regRowid);
|
| + }
|
| + /* The bottom of the loop
|
| + */
|
| + sqlite3VdbeResolveLabel(v, addrContinue);
|
| + if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
| + sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
|
| + }else{
|
| + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
|
| + }
|
| + if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
|
| + sqlite3VdbeResolveLabel(v, addrBreak);
|
| +}
|
| +
|
| +/*
|
| +** Return a pointer to a string containing the 'declaration type' of the
|
| +** expression pExpr. The string may be treated as static by the caller.
|
| +**
|
| +** Also try to estimate the size of the returned value and return that
|
| +** result in *pEstWidth.
|
| +**
|
| +** The declaration type is the exact datatype definition extracted from the
|
| +** original CREATE TABLE statement if the expression is a column. The
|
| +** declaration type for a ROWID field is INTEGER. Exactly when an expression
|
| +** is considered a column can be complex in the presence of subqueries. The
|
| +** result-set expression in all of the following SELECT statements is
|
| +** considered a column by this function.
|
| +**
|
| +** SELECT col FROM tbl;
|
| +** SELECT (SELECT col FROM tbl;
|
| +** SELECT (SELECT col FROM tbl);
|
| +** SELECT abc FROM (SELECT col AS abc FROM tbl);
|
| +**
|
| +** The declaration type for any expression other than a column is NULL.
|
| +**
|
| +** This routine has either 3 or 6 parameters depending on whether or not
|
| +** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
|
| +*/
|
| +#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
| +# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
|
| +#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
|
| +# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
|
| +#endif
|
| +static const char *columnTypeImpl(
|
| + NameContext *pNC,
|
| + Expr *pExpr,
|
| +#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
| + const char **pzOrigDb,
|
| + const char **pzOrigTab,
|
| + const char **pzOrigCol,
|
| +#endif
|
| + u8 *pEstWidth
|
| +){
|
| + char const *zType = 0;
|
| + int j;
|
| + u8 estWidth = 1;
|
| +#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
| + char const *zOrigDb = 0;
|
| + char const *zOrigTab = 0;
|
| + char const *zOrigCol = 0;
|
| +#endif
|
| +
|
| + assert( pExpr!=0 );
|
| + assert( pNC->pSrcList!=0 );
|
| + switch( pExpr->op ){
|
| + case TK_AGG_COLUMN:
|
| + case TK_COLUMN: {
|
| + /* The expression is a column. Locate the table the column is being
|
| + ** extracted from in NameContext.pSrcList. This table may be real
|
| + ** database table or a subquery.
|
| + */
|
| + Table *pTab = 0; /* Table structure column is extracted from */
|
| + Select *pS = 0; /* Select the column is extracted from */
|
| + int iCol = pExpr->iColumn; /* Index of column in pTab */
|
| + testcase( pExpr->op==TK_AGG_COLUMN );
|
| + testcase( pExpr->op==TK_COLUMN );
|
| + while( pNC && !pTab ){
|
| + SrcList *pTabList = pNC->pSrcList;
|
| + for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
|
| + if( j<pTabList->nSrc ){
|
| + pTab = pTabList->a[j].pTab;
|
| + pS = pTabList->a[j].pSelect;
|
| + }else{
|
| + pNC = pNC->pNext;
|
| + }
|
| + }
|
| +
|
| + if( pTab==0 ){
|
| + /* At one time, code such as "SELECT new.x" within a trigger would
|
| + ** cause this condition to run. Since then, we have restructured how
|
| + ** trigger code is generated and so this condition is no longer
|
| + ** possible. However, it can still be true for statements like
|
| + ** the following:
|
| + **
|
| + ** CREATE TABLE t1(col INTEGER);
|
| + ** SELECT (SELECT t1.col) FROM FROM t1;
|
| + **
|
| + ** when columnType() is called on the expression "t1.col" in the
|
| + ** sub-select. In this case, set the column type to NULL, even
|
| + ** though it should really be "INTEGER".
|
| + **
|
| + ** This is not a problem, as the column type of "t1.col" is never
|
| + ** used. When columnType() is called on the expression
|
| + ** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT
|
| + ** branch below. */
|
| + break;
|
| + }
|
| +
|
| + assert( pTab && pExpr->pTab==pTab );
|
| + if( pS ){
|
| + /* The "table" is actually a sub-select or a view in the FROM clause
|
| + ** of the SELECT statement. Return the declaration type and origin
|
| + ** data for the result-set column of the sub-select.
|
| + */
|
| + if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
|
| + /* If iCol is less than zero, then the expression requests the
|
| + ** rowid of the sub-select or view. This expression is legal (see
|
| + ** test case misc2.2.2) - it always evaluates to NULL.
|
| + **
|
| + ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been
|
| + ** caught already by name resolution.
|
| + */
|
| + NameContext sNC;
|
| + Expr *p = pS->pEList->a[iCol].pExpr;
|
| + sNC.pSrcList = pS->pSrc;
|
| + sNC.pNext = pNC;
|
| + sNC.pParse = pNC->pParse;
|
| + zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth);
|
| + }
|
| + }else if( pTab->pSchema ){
|
| + /* A real table */
|
| + assert( !pS );
|
| + if( iCol<0 ) iCol = pTab->iPKey;
|
| + assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
| +#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
| + if( iCol<0 ){
|
| + zType = "INTEGER";
|
| + zOrigCol = "rowid";
|
| + }else{
|
| + zType = pTab->aCol[iCol].zType;
|
| + zOrigCol = pTab->aCol[iCol].zName;
|
| + estWidth = pTab->aCol[iCol].szEst;
|
| + }
|
| + zOrigTab = pTab->zName;
|
| + if( pNC->pParse ){
|
| + int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
|
| + zOrigDb = pNC->pParse->db->aDb[iDb].zName;
|
| + }
|
| +#else
|
| + if( iCol<0 ){
|
| + zType = "INTEGER";
|
| + }else{
|
| + zType = pTab->aCol[iCol].zType;
|
| + estWidth = pTab->aCol[iCol].szEst;
|
| + }
|
| +#endif
|
| + }
|
| + break;
|
| + }
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| + case TK_SELECT: {
|
| + /* The expression is a sub-select. Return the declaration type and
|
| + ** origin info for the single column in the result set of the SELECT
|
| + ** statement.
|
| + */
|
| + NameContext sNC;
|
| + Select *pS = pExpr->x.pSelect;
|
| + Expr *p = pS->pEList->a[0].pExpr;
|
| + assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
| + sNC.pSrcList = pS->pSrc;
|
| + sNC.pNext = pNC;
|
| + sNC.pParse = pNC->pParse;
|
| + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth);
|
| + break;
|
| + }
|
| +#endif
|
| + }
|
| +
|
| +#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
| + if( pzOrigDb ){
|
| + assert( pzOrigTab && pzOrigCol );
|
| + *pzOrigDb = zOrigDb;
|
| + *pzOrigTab = zOrigTab;
|
| + *pzOrigCol = zOrigCol;
|
| + }
|
| +#endif
|
| + if( pEstWidth ) *pEstWidth = estWidth;
|
| + return zType;
|
| +}
|
| +
|
| +/*
|
| +** Generate code that will tell the VDBE the declaration types of columns
|
| +** in the result set.
|
| +*/
|
| +static void generateColumnTypes(
|
| + Parse *pParse, /* Parser context */
|
| + SrcList *pTabList, /* List of tables */
|
| + ExprList *pEList /* Expressions defining the result set */
|
| +){
|
| +#ifndef SQLITE_OMIT_DECLTYPE
|
| + Vdbe *v = pParse->pVdbe;
|
| + int i;
|
| + NameContext sNC;
|
| + sNC.pSrcList = pTabList;
|
| + sNC.pParse = pParse;
|
| + for(i=0; i<pEList->nExpr; i++){
|
| + Expr *p = pEList->a[i].pExpr;
|
| + const char *zType;
|
| +#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
| + const char *zOrigDb = 0;
|
| + const char *zOrigTab = 0;
|
| + const char *zOrigCol = 0;
|
| + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
|
| +
|
| + /* The vdbe must make its own copy of the column-type and other
|
| + ** column specific strings, in case the schema is reset before this
|
| + ** virtual machine is deleted.
|
| + */
|
| + sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, SQLITE_TRANSIENT);
|
| + sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
|
| + sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
|
| +#else
|
| + zType = columnType(&sNC, p, 0, 0, 0, 0);
|
| +#endif
|
| + sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
|
| + }
|
| +#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
|
| +}
|
| +
|
| +/*
|
| +** Generate code that will tell the VDBE the names of columns
|
| +** in the result set. This information is used to provide the
|
| +** azCol[] values in the callback.
|
| +*/
|
| +static void generateColumnNames(
|
| + Parse *pParse, /* Parser context */
|
| + SrcList *pTabList, /* List of tables */
|
| + ExprList *pEList /* Expressions defining the result set */
|
| +){
|
| + Vdbe *v = pParse->pVdbe;
|
| + int i, j;
|
| + sqlite3 *db = pParse->db;
|
| + int fullNames, shortNames;
|
| +
|
| +#ifndef SQLITE_OMIT_EXPLAIN
|
| + /* If this is an EXPLAIN, skip this step */
|
| + if( pParse->explain ){
|
| + return;
|
| + }
|
| +#endif
|
| +
|
| + if( pParse->colNamesSet || db->mallocFailed ) return;
|
| + assert( v!=0 );
|
| + assert( pTabList!=0 );
|
| + pParse->colNamesSet = 1;
|
| + fullNames = (db->flags & SQLITE_FullColNames)!=0;
|
| + shortNames = (db->flags & SQLITE_ShortColNames)!=0;
|
| + sqlite3VdbeSetNumCols(v, pEList->nExpr);
|
| + for(i=0; i<pEList->nExpr; i++){
|
| + Expr *p;
|
| + p = pEList->a[i].pExpr;
|
| + if( NEVER(p==0) ) continue;
|
| + if( pEList->a[i].zName ){
|
| + char *zName = pEList->a[i].zName;
|
| + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
|
| + }else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){
|
| + Table *pTab;
|
| + char *zCol;
|
| + int iCol = p->iColumn;
|
| + for(j=0; ALWAYS(j<pTabList->nSrc); j++){
|
| + if( pTabList->a[j].iCursor==p->iTable ) break;
|
| + }
|
| + assert( j<pTabList->nSrc );
|
| + pTab = pTabList->a[j].pTab;
|
| + if( iCol<0 ) iCol = pTab->iPKey;
|
| + assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
| + if( iCol<0 ){
|
| + zCol = "rowid";
|
| + }else{
|
| + zCol = pTab->aCol[iCol].zName;
|
| + }
|
| + if( !shortNames && !fullNames ){
|
| + sqlite3VdbeSetColName(v, i, COLNAME_NAME,
|
| + sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC);
|
| + }else if( fullNames ){
|
| + char *zName = 0;
|
| + zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol);
|
| + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC);
|
| + }else{
|
| + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT);
|
| + }
|
| + }else{
|
| + const char *z = pEList->a[i].zSpan;
|
| + z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z);
|
| + sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC);
|
| + }
|
| + }
|
| + generateColumnTypes(pParse, pTabList, pEList);
|
| +}
|
| +
|
| +/*
|
| +** Given an expression list (which is really the list of expressions
|
| +** that form the result set of a SELECT statement) compute appropriate
|
| +** column names for a table that would hold the expression list.
|
| +**
|
| +** All column names will be unique.
|
| +**
|
| +** Only the column names are computed. Column.zType, Column.zColl,
|
| +** and other fields of Column are zeroed.
|
| +**
|
| +** Return SQLITE_OK on success. If a memory allocation error occurs,
|
| +** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
|
| + Parse *pParse, /* Parsing context */
|
| + ExprList *pEList, /* Expr list from which to derive column names */
|
| + i16 *pnCol, /* Write the number of columns here */
|
| + Column **paCol /* Write the new column list here */
|
| +){
|
| + sqlite3 *db = pParse->db; /* Database connection */
|
| + int i, j; /* Loop counters */
|
| + u32 cnt; /* Index added to make the name unique */
|
| + Column *aCol, *pCol; /* For looping over result columns */
|
| + int nCol; /* Number of columns in the result set */
|
| + Expr *p; /* Expression for a single result column */
|
| + char *zName; /* Column name */
|
| + int nName; /* Size of name in zName[] */
|
| + Hash ht; /* Hash table of column names */
|
| +
|
| + sqlite3HashInit(&ht);
|
| + if( pEList ){
|
| + nCol = pEList->nExpr;
|
| + aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
|
| + testcase( aCol==0 );
|
| + }else{
|
| + nCol = 0;
|
| + aCol = 0;
|
| + }
|
| + assert( nCol==(i16)nCol );
|
| + *pnCol = nCol;
|
| + *paCol = aCol;
|
| +
|
| + for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
|
| + /* Get an appropriate name for the column
|
| + */
|
| + p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
|
| + if( (zName = pEList->a[i].zName)!=0 ){
|
| + /* If the column contains an "AS <name>" phrase, use <name> as the name */
|
| + }else{
|
| + Expr *pColExpr = p; /* The expression that is the result column name */
|
| + Table *pTab; /* Table associated with this expression */
|
| + while( pColExpr->op==TK_DOT ){
|
| + pColExpr = pColExpr->pRight;
|
| + assert( pColExpr!=0 );
|
| + }
|
| + if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
|
| + /* For columns use the column name name */
|
| + int iCol = pColExpr->iColumn;
|
| + pTab = pColExpr->pTab;
|
| + if( iCol<0 ) iCol = pTab->iPKey;
|
| + zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
|
| + }else if( pColExpr->op==TK_ID ){
|
| + assert( !ExprHasProperty(pColExpr, EP_IntValue) );
|
| + zName = pColExpr->u.zToken;
|
| + }else{
|
| + /* Use the original text of the column expression as its name */
|
| + zName = pEList->a[i].zSpan;
|
| + }
|
| + }
|
| + zName = sqlite3MPrintf(db, "%s", zName);
|
| +
|
| + /* Make sure the column name is unique. If the name is not unique,
|
| + ** append an integer to the name so that it becomes unique.
|
| + */
|
| + cnt = 0;
|
| + while( zName && sqlite3HashFind(&ht, zName)!=0 ){
|
| + nName = sqlite3Strlen30(zName);
|
| + if( nName>0 ){
|
| + for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
|
| + if( zName[j]==':' ) nName = j;
|
| + }
|
| + zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
|
| + if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
|
| + }
|
| + pCol->zName = zName;
|
| + sqlite3ColumnPropertiesFromName(0, pCol);
|
| + if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
|
| + db->mallocFailed = 1;
|
| + }
|
| + }
|
| + sqlite3HashClear(&ht);
|
| + if( db->mallocFailed ){
|
| + for(j=0; j<i; j++){
|
| + sqlite3DbFree(db, aCol[j].zName);
|
| + }
|
| + sqlite3DbFree(db, aCol);
|
| + *paCol = 0;
|
| + *pnCol = 0;
|
| + return SQLITE_NOMEM;
|
| + }
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Add type and collation information to a column list based on
|
| +** a SELECT statement.
|
| +**
|
| +** The column list presumably came from selectColumnNamesFromExprList().
|
| +** The column list has only names, not types or collations. This
|
| +** routine goes through and adds the types and collations.
|
| +**
|
| +** This routine requires that all identifiers in the SELECT
|
| +** statement be resolved.
|
| +*/
|
| +static void selectAddColumnTypeAndCollation(
|
| + Parse *pParse, /* Parsing contexts */
|
| + Table *pTab, /* Add column type information to this table */
|
| + Select *pSelect /* SELECT used to determine types and collations */
|
| +){
|
| + sqlite3 *db = pParse->db;
|
| + NameContext sNC;
|
| + Column *pCol;
|
| + CollSeq *pColl;
|
| + int i;
|
| + Expr *p;
|
| + struct ExprList_item *a;
|
| + u64 szAll = 0;
|
| +
|
| + assert( pSelect!=0 );
|
| + assert( (pSelect->selFlags & SF_Resolved)!=0 );
|
| + assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed );
|
| + if( db->mallocFailed ) return;
|
| + memset(&sNC, 0, sizeof(sNC));
|
| + sNC.pSrcList = pSelect->pSrc;
|
| + a = pSelect->pEList->a;
|
| + for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
| + p = a[i].pExpr;
|
| + if( pCol->zType==0 ){
|
| + pCol->zType = sqlite3DbStrDup(db,
|
| + columnType(&sNC, p,0,0,0, &pCol->szEst));
|
| + }
|
| + szAll += pCol->szEst;
|
| + pCol->affinity = sqlite3ExprAffinity(p);
|
| + if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
|
| + pColl = sqlite3ExprCollSeq(pParse, p);
|
| + if( pColl && pCol->zColl==0 ){
|
| + pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
|
| + }
|
| + }
|
| + pTab->szTabRow = sqlite3LogEst(szAll*4);
|
| +}
|
| +
|
| +/*
|
| +** Given a SELECT statement, generate a Table structure that describes
|
| +** the result set of that SELECT.
|
| +*/
|
| +SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
| + Table *pTab;
|
| + sqlite3 *db = pParse->db;
|
| + int savedFlags;
|
| +
|
| + savedFlags = db->flags;
|
| + db->flags &= ~SQLITE_FullColNames;
|
| + db->flags |= SQLITE_ShortColNames;
|
| + sqlite3SelectPrep(pParse, pSelect, 0);
|
| + if( pParse->nErr ) return 0;
|
| + while( pSelect->pPrior ) pSelect = pSelect->pPrior;
|
| + db->flags = savedFlags;
|
| + pTab = sqlite3DbMallocZero(db, sizeof(Table) );
|
| + if( pTab==0 ){
|
| + return 0;
|
| + }
|
| + /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
|
| + ** is disabled */
|
| + assert( db->lookaside.bEnabled==0 );
|
| + pTab->nRef = 1;
|
| + pTab->zName = 0;
|
| + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
| + sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
| + selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
| + pTab->iPKey = -1;
|
| + if( db->mallocFailed ){
|
| + sqlite3DeleteTable(db, pTab);
|
| + return 0;
|
| + }
|
| + return pTab;
|
| +}
|
| +
|
| +/*
|
| +** Get a VDBE for the given parser context. Create a new one if necessary.
|
| +** If an error occurs, return NULL and leave a message in pParse.
|
| +*/
|
| +SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
|
| + Vdbe *v = pParse->pVdbe;
|
| + if( v==0 ){
|
| + v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
|
| + if( v ) sqlite3VdbeAddOp0(v, OP_Init);
|
| + if( pParse->pToplevel==0
|
| + && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
|
| + ){
|
| + pParse->okConstFactor = 1;
|
| + }
|
| +
|
| + }
|
| + return v;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Compute the iLimit and iOffset fields of the SELECT based on the
|
| +** pLimit and pOffset expressions. pLimit and pOffset hold the expressions
|
| +** that appear in the original SQL statement after the LIMIT and OFFSET
|
| +** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
|
| +** are the integer memory register numbers for counters used to compute
|
| +** the limit and offset. If there is no limit and/or offset, then
|
| +** iLimit and iOffset are negative.
|
| +**
|
| +** This routine changes the values of iLimit and iOffset only if
|
| +** a limit or offset is defined by pLimit and pOffset. iLimit and
|
| +** iOffset should have been preset to appropriate default values (zero)
|
| +** prior to calling this routine.
|
| +**
|
| +** The iOffset register (if it exists) is initialized to the value
|
| +** of the OFFSET. The iLimit register is initialized to LIMIT. Register
|
| +** iOffset+1 is initialized to LIMIT+OFFSET.
|
| +**
|
| +** Only if pLimit!=0 or pOffset!=0 do the limit registers get
|
| +** redefined. The UNION ALL operator uses this property to force
|
| +** the reuse of the same limit and offset registers across multiple
|
| +** SELECT statements.
|
| +*/
|
| +static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
| + Vdbe *v = 0;
|
| + int iLimit = 0;
|
| + int iOffset;
|
| + int n;
|
| + if( p->iLimit ) return;
|
| +
|
| + /*
|
| + ** "LIMIT -1" always shows all rows. There is some
|
| + ** controversy about what the correct behavior should be.
|
| + ** The current implementation interprets "LIMIT 0" to mean
|
| + ** no rows.
|
| + */
|
| + sqlite3ExprCacheClear(pParse);
|
| + assert( p->pOffset==0 || p->pLimit!=0 );
|
| + if( p->pLimit ){
|
| + p->iLimit = iLimit = ++pParse->nMem;
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( v!=0 );
|
| + if( sqlite3ExprIsInteger(p->pLimit, &n) ){
|
| + sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit);
|
| + VdbeComment((v, "LIMIT counter"));
|
| + if( n==0 ){
|
| + sqlite3VdbeGoto(v, iBreak);
|
| + }else if( n>=0 && p->nSelectRow>(u64)n ){
|
| + p->nSelectRow = n;
|
| + }
|
| + }else{
|
| + sqlite3ExprCode(pParse, p->pLimit, iLimit);
|
| + sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v);
|
| + VdbeComment((v, "LIMIT counter"));
|
| + sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
|
| + }
|
| + if( p->pOffset ){
|
| + p->iOffset = iOffset = ++pParse->nMem;
|
| + pParse->nMem++; /* Allocate an extra register for limit+offset */
|
| + sqlite3ExprCode(pParse, p->pOffset, iOffset);
|
| + sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
|
| + VdbeComment((v, "OFFSET counter"));
|
| + sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iOffset, iOffset, 0);
|
| + sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
|
| + VdbeComment((v, "LIMIT+OFFSET"));
|
| + sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iLimit, iOffset+1, -1);
|
| + }
|
| + }
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
| +/*
|
| +** Return the appropriate collating sequence for the iCol-th column of
|
| +** the result set for the compound-select statement "p". Return NULL if
|
| +** the column has no default collating sequence.
|
| +**
|
| +** The collating sequence for the compound select is taken from the
|
| +** left-most term of the select that has a collating sequence.
|
| +*/
|
| +static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){
|
| + CollSeq *pRet;
|
| + if( p->pPrior ){
|
| + pRet = multiSelectCollSeq(pParse, p->pPrior, iCol);
|
| + }else{
|
| + pRet = 0;
|
| + }
|
| + assert( iCol>=0 );
|
| + /* iCol must be less than p->pEList->nExpr. Otherwise an error would
|
| + ** have been thrown during name resolution and we would not have gotten
|
| + ** this far */
|
| + if( pRet==0 && ALWAYS(iCol<p->pEList->nExpr) ){
|
| + pRet = sqlite3ExprCollSeq(pParse, p->pEList->a[iCol].pExpr);
|
| + }
|
| + return pRet;
|
| +}
|
| +
|
| +/*
|
| +** The select statement passed as the second parameter is a compound SELECT
|
| +** with an ORDER BY clause. This function allocates and returns a KeyInfo
|
| +** structure suitable for implementing the ORDER BY.
|
| +**
|
| +** Space to hold the KeyInfo structure is obtained from malloc. The calling
|
| +** function is responsible for ensuring that this structure is eventually
|
| +** freed.
|
| +*/
|
| +static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
|
| + ExprList *pOrderBy = p->pOrderBy;
|
| + int nOrderBy = p->pOrderBy->nExpr;
|
| + sqlite3 *db = pParse->db;
|
| + KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1);
|
| + if( pRet ){
|
| + int i;
|
| + for(i=0; i<nOrderBy; i++){
|
| + struct ExprList_item *pItem = &pOrderBy->a[i];
|
| + Expr *pTerm = pItem->pExpr;
|
| + CollSeq *pColl;
|
| +
|
| + if( pTerm->flags & EP_Collate ){
|
| + pColl = sqlite3ExprCollSeq(pParse, pTerm);
|
| + }else{
|
| + pColl = multiSelectCollSeq(pParse, p, pItem->u.x.iOrderByCol-1);
|
| + if( pColl==0 ) pColl = db->pDfltColl;
|
| + pOrderBy->a[i].pExpr =
|
| + sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName);
|
| + }
|
| + assert( sqlite3KeyInfoIsWriteable(pRet) );
|
| + pRet->aColl[i] = pColl;
|
| + pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder;
|
| + }
|
| + }
|
| +
|
| + return pRet;
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_CTE
|
| +/*
|
| +** This routine generates VDBE code to compute the content of a WITH RECURSIVE
|
| +** query of the form:
|
| +**
|
| +** <recursive-table> AS (<setup-query> UNION [ALL] <recursive-query>)
|
| +** \___________/ \_______________/
|
| +** p->pPrior p
|
| +**
|
| +**
|
| +** There is exactly one reference to the recursive-table in the FROM clause
|
| +** of recursive-query, marked with the SrcList->a[].fg.isRecursive flag.
|
| +**
|
| +** The setup-query runs once to generate an initial set of rows that go
|
| +** into a Queue table. Rows are extracted from the Queue table one by
|
| +** one. Each row extracted from Queue is output to pDest. Then the single
|
| +** extracted row (now in the iCurrent table) becomes the content of the
|
| +** recursive-table for a recursive-query run. The output of the recursive-query
|
| +** is added back into the Queue table. Then another row is extracted from Queue
|
| +** and the iteration continues until the Queue table is empty.
|
| +**
|
| +** If the compound query operator is UNION then no duplicate rows are ever
|
| +** inserted into the Queue table. The iDistinct table keeps a copy of all rows
|
| +** that have ever been inserted into Queue and causes duplicates to be
|
| +** discarded. If the operator is UNION ALL, then duplicates are allowed.
|
| +**
|
| +** If the query has an ORDER BY, then entries in the Queue table are kept in
|
| +** ORDER BY order and the first entry is extracted for each cycle. Without
|
| +** an ORDER BY, the Queue table is just a FIFO.
|
| +**
|
| +** If a LIMIT clause is provided, then the iteration stops after LIMIT rows
|
| +** have been output to pDest. A LIMIT of zero means to output no rows and a
|
| +** negative LIMIT means to output all rows. If there is also an OFFSET clause
|
| +** with a positive value, then the first OFFSET outputs are discarded rather
|
| +** than being sent to pDest. The LIMIT count does not begin until after OFFSET
|
| +** rows have been skipped.
|
| +*/
|
| +static void generateWithRecursiveQuery(
|
| + Parse *pParse, /* Parsing context */
|
| + Select *p, /* The recursive SELECT to be coded */
|
| + SelectDest *pDest /* What to do with query results */
|
| +){
|
| + SrcList *pSrc = p->pSrc; /* The FROM clause of the recursive query */
|
| + int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */
|
| + Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
|
| + Select *pSetup = p->pPrior; /* The setup query */
|
| + int addrTop; /* Top of the loop */
|
| + int addrCont, addrBreak; /* CONTINUE and BREAK addresses */
|
| + int iCurrent = 0; /* The Current table */
|
| + int regCurrent; /* Register holding Current table */
|
| + int iQueue; /* The Queue table */
|
| + int iDistinct = 0; /* To ensure unique results if UNION */
|
| + int eDest = SRT_Fifo; /* How to write to Queue */
|
| + SelectDest destQueue; /* SelectDest targetting the Queue table */
|
| + int i; /* Loop counter */
|
| + int rc; /* Result code */
|
| + ExprList *pOrderBy; /* The ORDER BY clause */
|
| + Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */
|
| + int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */
|
| +
|
| + /* Obtain authorization to do a recursive query */
|
| + if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return;
|
| +
|
| + /* Process the LIMIT and OFFSET clauses, if they exist */
|
| + addrBreak = sqlite3VdbeMakeLabel(v);
|
| + computeLimitRegisters(pParse, p, addrBreak);
|
| + pLimit = p->pLimit;
|
| + pOffset = p->pOffset;
|
| + regLimit = p->iLimit;
|
| + regOffset = p->iOffset;
|
| + p->pLimit = p->pOffset = 0;
|
| + p->iLimit = p->iOffset = 0;
|
| + pOrderBy = p->pOrderBy;
|
| +
|
| + /* Locate the cursor number of the Current table */
|
| + for(i=0; ALWAYS(i<pSrc->nSrc); i++){
|
| + if( pSrc->a[i].fg.isRecursive ){
|
| + iCurrent = pSrc->a[i].iCursor;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + /* Allocate cursors numbers for Queue and Distinct. The cursor number for
|
| + ** the Distinct table must be exactly one greater than Queue in order
|
| + ** for the SRT_DistFifo and SRT_DistQueue destinations to work. */
|
| + iQueue = pParse->nTab++;
|
| + if( p->op==TK_UNION ){
|
| + eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo;
|
| + iDistinct = pParse->nTab++;
|
| + }else{
|
| + eDest = pOrderBy ? SRT_Queue : SRT_Fifo;
|
| + }
|
| + sqlite3SelectDestInit(&destQueue, eDest, iQueue);
|
| +
|
| + /* Allocate cursors for Current, Queue, and Distinct. */
|
| + regCurrent = ++pParse->nMem;
|
| + sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol);
|
| + if( pOrderBy ){
|
| + KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1);
|
| + sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iQueue, pOrderBy->nExpr+2, 0,
|
| + (char*)pKeyInfo, P4_KEYINFO);
|
| + destQueue.pOrderBy = pOrderBy;
|
| + }else{
|
| + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iQueue, nCol);
|
| + }
|
| + VdbeComment((v, "Queue table"));
|
| + if( iDistinct ){
|
| + p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0);
|
| + p->selFlags |= SF_UsesEphemeral;
|
| + }
|
| +
|
| + /* Detach the ORDER BY clause from the compound SELECT */
|
| + p->pOrderBy = 0;
|
| +
|
| + /* Store the results of the setup-query in Queue. */
|
| + pSetup->pNext = 0;
|
| + rc = sqlite3Select(pParse, pSetup, &destQueue);
|
| + pSetup->pNext = p;
|
| + if( rc ) goto end_of_recursive_query;
|
| +
|
| + /* Find the next row in the Queue and output that row */
|
| + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v);
|
| +
|
| + /* Transfer the next row in Queue over to Current */
|
| + sqlite3VdbeAddOp1(v, OP_NullRow, iCurrent); /* To reset column cache */
|
| + if( pOrderBy ){
|
| + sqlite3VdbeAddOp3(v, OP_Column, iQueue, pOrderBy->nExpr+1, regCurrent);
|
| + }else{
|
| + sqlite3VdbeAddOp2(v, OP_RowData, iQueue, regCurrent);
|
| + }
|
| + sqlite3VdbeAddOp1(v, OP_Delete, iQueue);
|
| +
|
| + /* Output the single row in Current */
|
| + addrCont = sqlite3VdbeMakeLabel(v);
|
| + codeOffset(v, regOffset, addrCont);
|
| + selectInnerLoop(pParse, p, p->pEList, iCurrent,
|
| + 0, 0, pDest, addrCont, addrBreak);
|
| + if( regLimit ){
|
| + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
|
| + VdbeCoverage(v);
|
| + }
|
| + sqlite3VdbeResolveLabel(v, addrCont);
|
| +
|
| + /* Execute the recursive SELECT taking the single row in Current as
|
| + ** the value for the recursive-table. Store the results in the Queue.
|
| + */
|
| + if( p->selFlags & SF_Aggregate ){
|
| + sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
|
| + }else{
|
| + p->pPrior = 0;
|
| + sqlite3Select(pParse, p, &destQueue);
|
| + assert( p->pPrior==0 );
|
| + p->pPrior = pSetup;
|
| + }
|
| +
|
| + /* Keep running the loop until the Queue is empty */
|
| + sqlite3VdbeGoto(v, addrTop);
|
| + sqlite3VdbeResolveLabel(v, addrBreak);
|
| +
|
| +end_of_recursive_query:
|
| + sqlite3ExprListDelete(pParse->db, p->pOrderBy);
|
| + p->pOrderBy = pOrderBy;
|
| + p->pLimit = pLimit;
|
| + p->pOffset = pOffset;
|
| + return;
|
| +}
|
| +#endif /* SQLITE_OMIT_CTE */
|
| +
|
| +/* Forward references */
|
| +static int multiSelectOrderBy(
|
| + Parse *pParse, /* Parsing context */
|
| + Select *p, /* The right-most of SELECTs to be coded */
|
| + SelectDest *pDest /* What to do with query results */
|
| +);
|
| +
|
| +/*
|
| +** Handle the special case of a compound-select that originates from a
|
| +** VALUES clause. By handling this as a special case, we avoid deep
|
| +** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
|
| +** on a VALUES clause.
|
| +**
|
| +** Because the Select object originates from a VALUES clause:
|
| +** (1) It has no LIMIT or OFFSET
|
| +** (2) All terms are UNION ALL
|
| +** (3) There is no ORDER BY clause
|
| +*/
|
| +static int multiSelectValues(
|
| + Parse *pParse, /* Parsing context */
|
| + Select *p, /* The right-most of SELECTs to be coded */
|
| + SelectDest *pDest /* What to do with query results */
|
| +){
|
| + Select *pPrior;
|
| + int nRow = 1;
|
| + int rc = 0;
|
| + assert( p->selFlags & SF_MultiValue );
|
| + do{
|
| + assert( p->selFlags & SF_Values );
|
| + assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
|
| + assert( p->pLimit==0 );
|
| + assert( p->pOffset==0 );
|
| + assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
|
| + if( p->pPrior==0 ) break;
|
| + assert( p->pPrior->pNext==p );
|
| + p = p->pPrior;
|
| + nRow++;
|
| + }while(1);
|
| + while( p ){
|
| + pPrior = p->pPrior;
|
| + p->pPrior = 0;
|
| + rc = sqlite3Select(pParse, p, pDest);
|
| + p->pPrior = pPrior;
|
| + if( rc ) break;
|
| + p->nSelectRow = nRow;
|
| + p = p->pNext;
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** This routine is called to process a compound query form from
|
| +** two or more separate queries using UNION, UNION ALL, EXCEPT, or
|
| +** INTERSECT
|
| +**
|
| +** "p" points to the right-most of the two queries. the query on the
|
| +** left is p->pPrior. The left query could also be a compound query
|
| +** in which case this routine will be called recursively.
|
| +**
|
| +** The results of the total query are to be written into a destination
|
| +** of type eDest with parameter iParm.
|
| +**
|
| +** Example 1: Consider a three-way compound SQL statement.
|
| +**
|
| +** SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3
|
| +**
|
| +** This statement is parsed up as follows:
|
| +**
|
| +** SELECT c FROM t3
|
| +** |
|
| +** `-----> SELECT b FROM t2
|
| +** |
|
| +** `------> SELECT a FROM t1
|
| +**
|
| +** The arrows in the diagram above represent the Select.pPrior pointer.
|
| +** So if this routine is called with p equal to the t3 query, then
|
| +** pPrior will be the t2 query. p->op will be TK_UNION in this case.
|
| +**
|
| +** Notice that because of the way SQLite parses compound SELECTs, the
|
| +** individual selects always group from left to right.
|
| +*/
|
| +static int multiSelect(
|
| + Parse *pParse, /* Parsing context */
|
| + Select *p, /* The right-most of SELECTs to be coded */
|
| + SelectDest *pDest /* What to do with query results */
|
| +){
|
| + int rc = SQLITE_OK; /* Success code from a subroutine */
|
| + Select *pPrior; /* Another SELECT immediately to our left */
|
| + Vdbe *v; /* Generate code to this VDBE */
|
| + SelectDest dest; /* Alternative data destination */
|
| + Select *pDelete = 0; /* Chain of simple selects to delete */
|
| + sqlite3 *db; /* Database connection */
|
| +#ifndef SQLITE_OMIT_EXPLAIN
|
| + int iSub1 = 0; /* EQP id of left-hand query */
|
| + int iSub2 = 0; /* EQP id of right-hand query */
|
| +#endif
|
| +
|
| + /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
|
| + ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
|
| + */
|
| + assert( p && p->pPrior ); /* Calling function guarantees this much */
|
| + assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION );
|
| + db = pParse->db;
|
| + pPrior = p->pPrior;
|
| + dest = *pDest;
|
| + if( pPrior->pOrderBy ){
|
| + sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
|
| + selectOpName(p->op));
|
| + rc = 1;
|
| + goto multi_select_end;
|
| + }
|
| + if( pPrior->pLimit ){
|
| + sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
|
| + selectOpName(p->op));
|
| + rc = 1;
|
| + goto multi_select_end;
|
| + }
|
| +
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( v!=0 ); /* The VDBE already created by calling function */
|
| +
|
| + /* Create the destination temporary table if necessary
|
| + */
|
| + if( dest.eDest==SRT_EphemTab ){
|
| + assert( p->pEList );
|
| + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
|
| + sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
| + dest.eDest = SRT_Table;
|
| + }
|
| +
|
| + /* Special handling for a compound-select that originates as a VALUES clause.
|
| + */
|
| + if( p->selFlags & SF_MultiValue ){
|
| + rc = multiSelectValues(pParse, p, &dest);
|
| + goto multi_select_end;
|
| + }
|
| +
|
| + /* Make sure all SELECTs in the statement have the same number of elements
|
| + ** in their result sets.
|
| + */
|
| + assert( p->pEList && pPrior->pEList );
|
| + assert( p->pEList->nExpr==pPrior->pEList->nExpr );
|
| +
|
| +#ifndef SQLITE_OMIT_CTE
|
| + if( p->selFlags & SF_Recursive ){
|
| + generateWithRecursiveQuery(pParse, p, &dest);
|
| + }else
|
| +#endif
|
| +
|
| + /* Compound SELECTs that have an ORDER BY clause are handled separately.
|
| + */
|
| + if( p->pOrderBy ){
|
| + return multiSelectOrderBy(pParse, p, pDest);
|
| + }else
|
| +
|
| + /* Generate code for the left and right SELECT statements.
|
| + */
|
| + switch( p->op ){
|
| + case TK_ALL: {
|
| + int addr = 0;
|
| + int nLimit;
|
| + assert( !pPrior->pLimit );
|
| + pPrior->iLimit = p->iLimit;
|
| + pPrior->iOffset = p->iOffset;
|
| + pPrior->pLimit = p->pLimit;
|
| + pPrior->pOffset = p->pOffset;
|
| + explainSetInteger(iSub1, pParse->iNextSelectId);
|
| + rc = sqlite3Select(pParse, pPrior, &dest);
|
| + p->pLimit = 0;
|
| + p->pOffset = 0;
|
| + if( rc ){
|
| + goto multi_select_end;
|
| + }
|
| + p->pPrior = 0;
|
| + p->iLimit = pPrior->iLimit;
|
| + p->iOffset = pPrior->iOffset;
|
| + if( p->iLimit ){
|
| + addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
|
| + VdbeComment((v, "Jump ahead if LIMIT reached"));
|
| + if( p->iOffset ){
|
| + sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iOffset, p->iOffset, 0);
|
| + sqlite3VdbeAddOp3(v, OP_Add, p->iLimit, p->iOffset, p->iOffset+1);
|
| + sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iLimit, p->iOffset+1, -1);
|
| + }
|
| + }
|
| + explainSetInteger(iSub2, pParse->iNextSelectId);
|
| + rc = sqlite3Select(pParse, p, &dest);
|
| + testcase( rc!=SQLITE_OK );
|
| + pDelete = p->pPrior;
|
| + p->pPrior = pPrior;
|
| + p->nSelectRow += pPrior->nSelectRow;
|
| + if( pPrior->pLimit
|
| + && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
|
| + && nLimit>0 && p->nSelectRow > (u64)nLimit
|
| + ){
|
| + p->nSelectRow = nLimit;
|
| + }
|
| + if( addr ){
|
| + sqlite3VdbeJumpHere(v, addr);
|
| + }
|
| + break;
|
| + }
|
| + case TK_EXCEPT:
|
| + case TK_UNION: {
|
| + int unionTab; /* Cursor number of the temporary table holding result */
|
| + u8 op = 0; /* One of the SRT_ operations to apply to self */
|
| + int priorOp; /* The SRT_ operation to apply to prior selects */
|
| + Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */
|
| + int addr;
|
| + SelectDest uniondest;
|
| +
|
| + testcase( p->op==TK_EXCEPT );
|
| + testcase( p->op==TK_UNION );
|
| + priorOp = SRT_Union;
|
| + if( dest.eDest==priorOp ){
|
| + /* We can reuse a temporary table generated by a SELECT to our
|
| + ** right.
|
| + */
|
| + assert( p->pLimit==0 ); /* Not allowed on leftward elements */
|
| + assert( p->pOffset==0 ); /* Not allowed on leftward elements */
|
| + unionTab = dest.iSDParm;
|
| + }else{
|
| + /* We will need to create our own temporary table to hold the
|
| + ** intermediate results.
|
| + */
|
| + unionTab = pParse->nTab++;
|
| + assert( p->pOrderBy==0 );
|
| + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
|
| + assert( p->addrOpenEphm[0] == -1 );
|
| + p->addrOpenEphm[0] = addr;
|
| + findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
| + assert( p->pEList );
|
| + }
|
| +
|
| + /* Code the SELECT statements to our left
|
| + */
|
| + assert( !pPrior->pOrderBy );
|
| + sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
|
| + explainSetInteger(iSub1, pParse->iNextSelectId);
|
| + rc = sqlite3Select(pParse, pPrior, &uniondest);
|
| + if( rc ){
|
| + goto multi_select_end;
|
| + }
|
| +
|
| + /* Code the current SELECT statement
|
| + */
|
| + if( p->op==TK_EXCEPT ){
|
| + op = SRT_Except;
|
| + }else{
|
| + assert( p->op==TK_UNION );
|
| + op = SRT_Union;
|
| + }
|
| + p->pPrior = 0;
|
| + pLimit = p->pLimit;
|
| + p->pLimit = 0;
|
| + pOffset = p->pOffset;
|
| + p->pOffset = 0;
|
| + uniondest.eDest = op;
|
| + explainSetInteger(iSub2, pParse->iNextSelectId);
|
| + rc = sqlite3Select(pParse, p, &uniondest);
|
| + testcase( rc!=SQLITE_OK );
|
| + /* Query flattening in sqlite3Select() might refill p->pOrderBy.
|
| + ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
|
| + sqlite3ExprListDelete(db, p->pOrderBy);
|
| + pDelete = p->pPrior;
|
| + p->pPrior = pPrior;
|
| + p->pOrderBy = 0;
|
| + if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
|
| + sqlite3ExprDelete(db, p->pLimit);
|
| + p->pLimit = pLimit;
|
| + p->pOffset = pOffset;
|
| + p->iLimit = 0;
|
| + p->iOffset = 0;
|
| +
|
| + /* Convert the data in the temporary table into whatever form
|
| + ** it is that we currently need.
|
| + */
|
| + assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
|
| + if( dest.eDest!=priorOp ){
|
| + int iCont, iBreak, iStart;
|
| + assert( p->pEList );
|
| + if( dest.eDest==SRT_Output ){
|
| + Select *pFirst = p;
|
| + while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
| + generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
|
| + }
|
| + iBreak = sqlite3VdbeMakeLabel(v);
|
| + iCont = sqlite3VdbeMakeLabel(v);
|
| + computeLimitRegisters(pParse, p, iBreak);
|
| + sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
|
| + iStart = sqlite3VdbeCurrentAddr(v);
|
| + selectInnerLoop(pParse, p, p->pEList, unionTab,
|
| + 0, 0, &dest, iCont, iBreak);
|
| + sqlite3VdbeResolveLabel(v, iCont);
|
| + sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
|
| + sqlite3VdbeResolveLabel(v, iBreak);
|
| + sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0);
|
| + }
|
| + break;
|
| + }
|
| + default: assert( p->op==TK_INTERSECT ); {
|
| + int tab1, tab2;
|
| + int iCont, iBreak, iStart;
|
| + Expr *pLimit, *pOffset;
|
| + int addr;
|
| + SelectDest intersectdest;
|
| + int r1;
|
| +
|
| + /* INTERSECT is different from the others since it requires
|
| + ** two temporary tables. Hence it has its own case. Begin
|
| + ** by allocating the tables we will need.
|
| + */
|
| + tab1 = pParse->nTab++;
|
| + tab2 = pParse->nTab++;
|
| + assert( p->pOrderBy==0 );
|
| +
|
| + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
|
| + assert( p->addrOpenEphm[0] == -1 );
|
| + p->addrOpenEphm[0] = addr;
|
| + findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
| + assert( p->pEList );
|
| +
|
| + /* Code the SELECTs to our left into temporary table "tab1".
|
| + */
|
| + sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
|
| + explainSetInteger(iSub1, pParse->iNextSelectId);
|
| + rc = sqlite3Select(pParse, pPrior, &intersectdest);
|
| + if( rc ){
|
| + goto multi_select_end;
|
| + }
|
| +
|
| + /* Code the current SELECT into temporary table "tab2"
|
| + */
|
| + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0);
|
| + assert( p->addrOpenEphm[1] == -1 );
|
| + p->addrOpenEphm[1] = addr;
|
| + p->pPrior = 0;
|
| + pLimit = p->pLimit;
|
| + p->pLimit = 0;
|
| + pOffset = p->pOffset;
|
| + p->pOffset = 0;
|
| + intersectdest.iSDParm = tab2;
|
| + explainSetInteger(iSub2, pParse->iNextSelectId);
|
| + rc = sqlite3Select(pParse, p, &intersectdest);
|
| + testcase( rc!=SQLITE_OK );
|
| + pDelete = p->pPrior;
|
| + p->pPrior = pPrior;
|
| + if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
|
| + sqlite3ExprDelete(db, p->pLimit);
|
| + p->pLimit = pLimit;
|
| + p->pOffset = pOffset;
|
| +
|
| + /* Generate code to take the intersection of the two temporary
|
| + ** tables.
|
| + */
|
| + assert( p->pEList );
|
| + if( dest.eDest==SRT_Output ){
|
| + Select *pFirst = p;
|
| + while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
| + generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
|
| + }
|
| + iBreak = sqlite3VdbeMakeLabel(v);
|
| + iCont = sqlite3VdbeMakeLabel(v);
|
| + computeLimitRegisters(pParse, p, iBreak);
|
| + sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
|
| + r1 = sqlite3GetTempReg(pParse);
|
| + iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
|
| + sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| + selectInnerLoop(pParse, p, p->pEList, tab1,
|
| + 0, 0, &dest, iCont, iBreak);
|
| + sqlite3VdbeResolveLabel(v, iCont);
|
| + sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
|
| + sqlite3VdbeResolveLabel(v, iBreak);
|
| + sqlite3VdbeAddOp2(v, OP_Close, tab2, 0);
|
| + sqlite3VdbeAddOp2(v, OP_Close, tab1, 0);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + explainComposite(pParse, p->op, iSub1, iSub2, p->op!=TK_ALL);
|
| +
|
| + /* Compute collating sequences used by
|
| + ** temporary tables needed to implement the compound select.
|
| + ** Attach the KeyInfo structure to all temporary tables.
|
| + **
|
| + ** This section is run by the right-most SELECT statement only.
|
| + ** SELECT statements to the left always skip this part. The right-most
|
| + ** SELECT might also skip this part if it has no ORDER BY clause and
|
| + ** no temp tables are required.
|
| + */
|
| + if( p->selFlags & SF_UsesEphemeral ){
|
| + int i; /* Loop counter */
|
| + KeyInfo *pKeyInfo; /* Collating sequence for the result set */
|
| + Select *pLoop; /* For looping through SELECT statements */
|
| + CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */
|
| + int nCol; /* Number of columns in result set */
|
| +
|
| + assert( p->pNext==0 );
|
| + nCol = p->pEList->nExpr;
|
| + pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
|
| + if( !pKeyInfo ){
|
| + rc = SQLITE_NOMEM;
|
| + goto multi_select_end;
|
| + }
|
| + for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
|
| + *apColl = multiSelectCollSeq(pParse, p, i);
|
| + if( 0==*apColl ){
|
| + *apColl = db->pDfltColl;
|
| + }
|
| + }
|
| +
|
| + for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
|
| + for(i=0; i<2; i++){
|
| + int addr = pLoop->addrOpenEphm[i];
|
| + if( addr<0 ){
|
| + /* If [0] is unused then [1] is also unused. So we can
|
| + ** always safely abort as soon as the first unused slot is found */
|
| + assert( pLoop->addrOpenEphm[1]<0 );
|
| + break;
|
| + }
|
| + sqlite3VdbeChangeP2(v, addr, nCol);
|
| + sqlite3VdbeChangeP4(v, addr, (char*)sqlite3KeyInfoRef(pKeyInfo),
|
| + P4_KEYINFO);
|
| + pLoop->addrOpenEphm[i] = -1;
|
| + }
|
| + }
|
| + sqlite3KeyInfoUnref(pKeyInfo);
|
| + }
|
| +
|
| +multi_select_end:
|
| + pDest->iSdst = dest.iSdst;
|
| + pDest->nSdst = dest.nSdst;
|
| + sqlite3SelectDelete(db, pDelete);
|
| + return rc;
|
| +}
|
| +#endif /* SQLITE_OMIT_COMPOUND_SELECT */
|
| +
|
| +/*
|
| +** Error message for when two or more terms of a compound select have different
|
| +** size result sets.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
|
| + if( p->selFlags & SF_Values ){
|
| + sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
|
| + }else{
|
| + sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
|
| + " do not have the same number of result columns", selectOpName(p->op));
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Code an output subroutine for a coroutine implementation of a
|
| +** SELECT statment.
|
| +**
|
| +** The data to be output is contained in pIn->iSdst. There are
|
| +** pIn->nSdst columns to be output. pDest is where the output should
|
| +** be sent.
|
| +**
|
| +** regReturn is the number of the register holding the subroutine
|
| +** return address.
|
| +**
|
| +** If regPrev>0 then it is the first register in a vector that
|
| +** records the previous output. mem[regPrev] is a flag that is false
|
| +** if there has been no previous output. If regPrev>0 then code is
|
| +** generated to suppress duplicates. pKeyInfo is used for comparing
|
| +** keys.
|
| +**
|
| +** If the LIMIT found in p->iLimit is reached, jump immediately to
|
| +** iBreak.
|
| +*/
|
| +static int generateOutputSubroutine(
|
| + Parse *pParse, /* Parsing context */
|
| + Select *p, /* The SELECT statement */
|
| + SelectDest *pIn, /* Coroutine supplying data */
|
| + SelectDest *pDest, /* Where to send the data */
|
| + int regReturn, /* The return address register */
|
| + int regPrev, /* Previous result register. No uniqueness if 0 */
|
| + KeyInfo *pKeyInfo, /* For comparing with previous entry */
|
| + int iBreak /* Jump here if we hit the LIMIT */
|
| +){
|
| + Vdbe *v = pParse->pVdbe;
|
| + int iContinue;
|
| + int addr;
|
| +
|
| + addr = sqlite3VdbeCurrentAddr(v);
|
| + iContinue = sqlite3VdbeMakeLabel(v);
|
| +
|
| + /* Suppress duplicates for UNION, EXCEPT, and INTERSECT
|
| + */
|
| + if( regPrev ){
|
| + int addr1, addr2;
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v);
|
| + addr2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst,
|
| + (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
|
| + sqlite3VdbeAddOp3(v, OP_Jump, addr2+2, iContinue, addr2+2); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev);
|
| + }
|
| + if( pParse->db->mallocFailed ) return 0;
|
| +
|
| + /* Suppress the first OFFSET entries if there is an OFFSET clause
|
| + */
|
| + codeOffset(v, p->iOffset, iContinue);
|
| +
|
| + assert( pDest->eDest!=SRT_Exists );
|
| + assert( pDest->eDest!=SRT_Table );
|
| + switch( pDest->eDest ){
|
| + /* Store the result as data using a unique key.
|
| + */
|
| + case SRT_EphemTab: {
|
| + int r1 = sqlite3GetTempReg(pParse);
|
| + int r2 = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1);
|
| + sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iSDParm, r2);
|
| + sqlite3VdbeAddOp3(v, OP_Insert, pDest->iSDParm, r1, r2);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| + sqlite3ReleaseTempReg(pParse, r2);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| + break;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| + /* If we are creating a set for an "expr IN (SELECT ...)" construct,
|
| + ** then there should be a single item on the stack. Write this
|
| + ** item into the set table with bogus data.
|
| + */
|
| + case SRT_Set: {
|
| + int r1;
|
| + assert( pIn->nSdst==1 || pParse->nErr>0 );
|
| + pDest->affSdst =
|
| + sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
|
| + r1 = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1);
|
| + sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| + break;
|
| + }
|
| +
|
| + /* If this is a scalar select that is part of an expression, then
|
| + ** store the results in the appropriate memory cell and break out
|
| + ** of the scan loop.
|
| + */
|
| + case SRT_Mem: {
|
| + assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 );
|
| + sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1);
|
| + /* The LIMIT clause will jump out of the loop for us */
|
| + break;
|
| + }
|
| +#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
|
| +
|
| + /* The results are stored in a sequence of registers
|
| + ** starting at pDest->iSdst. Then the co-routine yields.
|
| + */
|
| + case SRT_Coroutine: {
|
| + if( pDest->iSdst==0 ){
|
| + pDest->iSdst = sqlite3GetTempRange(pParse, pIn->nSdst);
|
| + pDest->nSdst = pIn->nSdst;
|
| + }
|
| + sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pIn->nSdst);
|
| + sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
|
| + break;
|
| + }
|
| +
|
| + /* If none of the above, then the result destination must be
|
| + ** SRT_Output. This routine is never called with any other
|
| + ** destination other than the ones handled above or SRT_Output.
|
| + **
|
| + ** For SRT_Output, results are stored in a sequence of registers.
|
| + ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to
|
| + ** return the next row of result.
|
| + */
|
| + default: {
|
| + assert( pDest->eDest==SRT_Output );
|
| + sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst);
|
| + sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + /* Jump to the end of the loop if the LIMIT is reached.
|
| + */
|
| + if( p->iLimit ){
|
| + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
|
| + }
|
| +
|
| + /* Generate the subroutine return
|
| + */
|
| + sqlite3VdbeResolveLabel(v, iContinue);
|
| + sqlite3VdbeAddOp1(v, OP_Return, regReturn);
|
| +
|
| + return addr;
|
| +}
|
| +
|
| +/*
|
| +** Alternative compound select code generator for cases when there
|
| +** is an ORDER BY clause.
|
| +**
|
| +** We assume a query of the following form:
|
| +**
|
| +** <selectA> <operator> <selectB> ORDER BY <orderbylist>
|
| +**
|
| +** <operator> is one of UNION ALL, UNION, EXCEPT, or INTERSECT. The idea
|
| +** is to code both <selectA> and <selectB> with the ORDER BY clause as
|
| +** co-routines. Then run the co-routines in parallel and merge the results
|
| +** into the output. In addition to the two coroutines (called selectA and
|
| +** selectB) there are 7 subroutines:
|
| +**
|
| +** outA: Move the output of the selectA coroutine into the output
|
| +** of the compound query.
|
| +**
|
| +** outB: Move the output of the selectB coroutine into the output
|
| +** of the compound query. (Only generated for UNION and
|
| +** UNION ALL. EXCEPT and INSERTSECT never output a row that
|
| +** appears only in B.)
|
| +**
|
| +** AltB: Called when there is data from both coroutines and A<B.
|
| +**
|
| +** AeqB: Called when there is data from both coroutines and A==B.
|
| +**
|
| +** AgtB: Called when there is data from both coroutines and A>B.
|
| +**
|
| +** EofA: Called when data is exhausted from selectA.
|
| +**
|
| +** EofB: Called when data is exhausted from selectB.
|
| +**
|
| +** The implementation of the latter five subroutines depend on which
|
| +** <operator> is used:
|
| +**
|
| +**
|
| +** UNION ALL UNION EXCEPT INTERSECT
|
| +** ------------- ----------------- -------------- -----------------
|
| +** AltB: outA, nextA outA, nextA outA, nextA nextA
|
| +**
|
| +** AeqB: outA, nextA nextA nextA outA, nextA
|
| +**
|
| +** AgtB: outB, nextB outB, nextB nextB nextB
|
| +**
|
| +** EofA: outB, nextB outB, nextB halt halt
|
| +**
|
| +** EofB: outA, nextA outA, nextA outA, nextA halt
|
| +**
|
| +** In the AltB, AeqB, and AgtB subroutines, an EOF on A following nextA
|
| +** causes an immediate jump to EofA and an EOF on B following nextB causes
|
| +** an immediate jump to EofB. Within EofA and EofB, and EOF on entry or
|
| +** following nextX causes a jump to the end of the select processing.
|
| +**
|
| +** Duplicate removal in the UNION, EXCEPT, and INTERSECT cases is handled
|
| +** within the output subroutine. The regPrev register set holds the previously
|
| +** output value. A comparison is made against this value and the output
|
| +** is skipped if the next results would be the same as the previous.
|
| +**
|
| +** The implementation plan is to implement the two coroutines and seven
|
| +** subroutines first, then put the control logic at the bottom. Like this:
|
| +**
|
| +** goto Init
|
| +** coA: coroutine for left query (A)
|
| +** coB: coroutine for right query (B)
|
| +** outA: output one row of A
|
| +** outB: output one row of B (UNION and UNION ALL only)
|
| +** EofA: ...
|
| +** EofB: ...
|
| +** AltB: ...
|
| +** AeqB: ...
|
| +** AgtB: ...
|
| +** Init: initialize coroutine registers
|
| +** yield coA
|
| +** if eof(A) goto EofA
|
| +** yield coB
|
| +** if eof(B) goto EofB
|
| +** Cmpr: Compare A, B
|
| +** Jump AltB, AeqB, AgtB
|
| +** End: ...
|
| +**
|
| +** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not
|
| +** actually called using Gosub and they do not Return. EofA and EofB loop
|
| +** until all data is exhausted then jump to the "end" labe. AltB, AeqB,
|
| +** and AgtB jump to either L2 or to one of EofA or EofB.
|
| +*/
|
| +#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
| +static int multiSelectOrderBy(
|
| + Parse *pParse, /* Parsing context */
|
| + Select *p, /* The right-most of SELECTs to be coded */
|
| + SelectDest *pDest /* What to do with query results */
|
| +){
|
| + int i, j; /* Loop counters */
|
| + Select *pPrior; /* Another SELECT immediately to our left */
|
| + Vdbe *v; /* Generate code to this VDBE */
|
| + SelectDest destA; /* Destination for coroutine A */
|
| + SelectDest destB; /* Destination for coroutine B */
|
| + int regAddrA; /* Address register for select-A coroutine */
|
| + int regAddrB; /* Address register for select-B coroutine */
|
| + int addrSelectA; /* Address of the select-A coroutine */
|
| + int addrSelectB; /* Address of the select-B coroutine */
|
| + int regOutA; /* Address register for the output-A subroutine */
|
| + int regOutB; /* Address register for the output-B subroutine */
|
| + int addrOutA; /* Address of the output-A subroutine */
|
| + int addrOutB = 0; /* Address of the output-B subroutine */
|
| + int addrEofA; /* Address of the select-A-exhausted subroutine */
|
| + int addrEofA_noB; /* Alternate addrEofA if B is uninitialized */
|
| + int addrEofB; /* Address of the select-B-exhausted subroutine */
|
| + int addrAltB; /* Address of the A<B subroutine */
|
| + int addrAeqB; /* Address of the A==B subroutine */
|
| + int addrAgtB; /* Address of the A>B subroutine */
|
| + int regLimitA; /* Limit register for select-A */
|
| + int regLimitB; /* Limit register for select-A */
|
| + int regPrev; /* A range of registers to hold previous output */
|
| + int savedLimit; /* Saved value of p->iLimit */
|
| + int savedOffset; /* Saved value of p->iOffset */
|
| + int labelCmpr; /* Label for the start of the merge algorithm */
|
| + int labelEnd; /* Label for the end of the overall SELECT stmt */
|
| + int addr1; /* Jump instructions that get retargetted */
|
| + int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
|
| + KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
|
| + KeyInfo *pKeyMerge; /* Comparison information for merging rows */
|
| + sqlite3 *db; /* Database connection */
|
| + ExprList *pOrderBy; /* The ORDER BY clause */
|
| + int nOrderBy; /* Number of terms in the ORDER BY clause */
|
| + int *aPermute; /* Mapping from ORDER BY terms to result set columns */
|
| +#ifndef SQLITE_OMIT_EXPLAIN
|
| + int iSub1; /* EQP id of left-hand query */
|
| + int iSub2; /* EQP id of right-hand query */
|
| +#endif
|
| +
|
| + assert( p->pOrderBy!=0 );
|
| + assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
|
| + db = pParse->db;
|
| + v = pParse->pVdbe;
|
| + assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */
|
| + labelEnd = sqlite3VdbeMakeLabel(v);
|
| + labelCmpr = sqlite3VdbeMakeLabel(v);
|
| +
|
| +
|
| + /* Patch up the ORDER BY clause
|
| + */
|
| + op = p->op;
|
| + pPrior = p->pPrior;
|
| + assert( pPrior->pOrderBy==0 );
|
| + pOrderBy = p->pOrderBy;
|
| + assert( pOrderBy );
|
| + nOrderBy = pOrderBy->nExpr;
|
| +
|
| + /* For operators other than UNION ALL we have to make sure that
|
| + ** the ORDER BY clause covers every term of the result set. Add
|
| + ** terms to the ORDER BY clause as necessary.
|
| + */
|
| + if( op!=TK_ALL ){
|
| + for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){
|
| + struct ExprList_item *pItem;
|
| + for(j=0, pItem=pOrderBy->a; j<nOrderBy; j++, pItem++){
|
| + assert( pItem->u.x.iOrderByCol>0 );
|
| + if( pItem->u.x.iOrderByCol==i ) break;
|
| + }
|
| + if( j==nOrderBy ){
|
| + Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
|
| + if( pNew==0 ) return SQLITE_NOMEM;
|
| + pNew->flags |= EP_IntValue;
|
| + pNew->u.iValue = i;
|
| + pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
|
| + if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Compute the comparison permutation and keyinfo that is used with
|
| + ** the permutation used to determine if the next
|
| + ** row of results comes from selectA or selectB. Also add explicit
|
| + ** collations to the ORDER BY clause terms so that when the subqueries
|
| + ** to the right and the left are evaluated, they use the correct
|
| + ** collation.
|
| + */
|
| + aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy);
|
| + if( aPermute ){
|
| + struct ExprList_item *pItem;
|
| + for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
|
| + assert( pItem->u.x.iOrderByCol>0 );
|
| + assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
|
| + aPermute[i] = pItem->u.x.iOrderByCol - 1;
|
| + }
|
| + pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
|
| + }else{
|
| + pKeyMerge = 0;
|
| + }
|
| +
|
| + /* Reattach the ORDER BY clause to the query.
|
| + */
|
| + p->pOrderBy = pOrderBy;
|
| + pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
|
| +
|
| + /* Allocate a range of temporary registers and the KeyInfo needed
|
| + ** for the logic that removes duplicate result rows when the
|
| + ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL).
|
| + */
|
| + if( op==TK_ALL ){
|
| + regPrev = 0;
|
| + }else{
|
| + int nExpr = p->pEList->nExpr;
|
| + assert( nOrderBy>=nExpr || db->mallocFailed );
|
| + regPrev = pParse->nMem+1;
|
| + pParse->nMem += nExpr+1;
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
|
| + pKeyDup = sqlite3KeyInfoAlloc(db, nExpr, 1);
|
| + if( pKeyDup ){
|
| + assert( sqlite3KeyInfoIsWriteable(pKeyDup) );
|
| + for(i=0; i<nExpr; i++){
|
| + pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i);
|
| + pKeyDup->aSortOrder[i] = 0;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Separate the left and the right query from one another
|
| + */
|
| + p->pPrior = 0;
|
| + pPrior->pNext = 0;
|
| + sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
|
| + if( pPrior->pPrior==0 ){
|
| + sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
|
| + }
|
| +
|
| + /* Compute the limit registers */
|
| + computeLimitRegisters(pParse, p, labelEnd);
|
| + if( p->iLimit && op==TK_ALL ){
|
| + regLimitA = ++pParse->nMem;
|
| + regLimitB = ++pParse->nMem;
|
| + sqlite3VdbeAddOp2(v, OP_Copy, p->iOffset ? p->iOffset+1 : p->iLimit,
|
| + regLimitA);
|
| + sqlite3VdbeAddOp2(v, OP_Copy, regLimitA, regLimitB);
|
| + }else{
|
| + regLimitA = regLimitB = 0;
|
| + }
|
| + sqlite3ExprDelete(db, p->pLimit);
|
| + p->pLimit = 0;
|
| + sqlite3ExprDelete(db, p->pOffset);
|
| + p->pOffset = 0;
|
| +
|
| + regAddrA = ++pParse->nMem;
|
| + regAddrB = ++pParse->nMem;
|
| + regOutA = ++pParse->nMem;
|
| + regOutB = ++pParse->nMem;
|
| + sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
|
| + sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
|
| +
|
| + /* Generate a coroutine to evaluate the SELECT statement to the
|
| + ** left of the compound operator - the "A" select.
|
| + */
|
| + addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
|
| + addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
|
| + VdbeComment((v, "left SELECT"));
|
| + pPrior->iLimit = regLimitA;
|
| + explainSetInteger(iSub1, pParse->iNextSelectId);
|
| + sqlite3Select(pParse, pPrior, &destA);
|
| + sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| +
|
| + /* Generate a coroutine to evaluate the SELECT statement on
|
| + ** the right - the "B" select
|
| + */
|
| + addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
|
| + addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
|
| + VdbeComment((v, "right SELECT"));
|
| + savedLimit = p->iLimit;
|
| + savedOffset = p->iOffset;
|
| + p->iLimit = regLimitB;
|
| + p->iOffset = 0;
|
| + explainSetInteger(iSub2, pParse->iNextSelectId);
|
| + sqlite3Select(pParse, p, &destB);
|
| + p->iLimit = savedLimit;
|
| + p->iOffset = savedOffset;
|
| + sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
|
| +
|
| + /* Generate a subroutine that outputs the current row of the A
|
| + ** select as the next output row of the compound select.
|
| + */
|
| + VdbeNoopComment((v, "Output routine for A"));
|
| + addrOutA = generateOutputSubroutine(pParse,
|
| + p, &destA, pDest, regOutA,
|
| + regPrev, pKeyDup, labelEnd);
|
| +
|
| + /* Generate a subroutine that outputs the current row of the B
|
| + ** select as the next output row of the compound select.
|
| + */
|
| + if( op==TK_ALL || op==TK_UNION ){
|
| + VdbeNoopComment((v, "Output routine for B"));
|
| + addrOutB = generateOutputSubroutine(pParse,
|
| + p, &destB, pDest, regOutB,
|
| + regPrev, pKeyDup, labelEnd);
|
| + }
|
| + sqlite3KeyInfoUnref(pKeyDup);
|
| +
|
| + /* Generate a subroutine to run when the results from select A
|
| + ** are exhausted and only data in select B remains.
|
| + */
|
| + if( op==TK_EXCEPT || op==TK_INTERSECT ){
|
| + addrEofA_noB = addrEofA = labelEnd;
|
| + }else{
|
| + VdbeNoopComment((v, "eof-A subroutine"));
|
| + addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
| + addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
|
| + VdbeCoverage(v);
|
| + sqlite3VdbeGoto(v, addrEofA);
|
| + p->nSelectRow += pPrior->nSelectRow;
|
| + }
|
| +
|
| + /* Generate a subroutine to run when the results from select B
|
| + ** are exhausted and only data in select A remains.
|
| + */
|
| + if( op==TK_INTERSECT ){
|
| + addrEofB = addrEofA;
|
| + if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
|
| + }else{
|
| + VdbeNoopComment((v, "eof-B subroutine"));
|
| + addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
| + sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v);
|
| + sqlite3VdbeGoto(v, addrEofB);
|
| + }
|
| +
|
| + /* Generate code to handle the case of A<B
|
| + */
|
| + VdbeNoopComment((v, "A-lt-B subroutine"));
|
| + addrAltB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
| + sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA); VdbeCoverage(v);
|
| + sqlite3VdbeGoto(v, labelCmpr);
|
| +
|
| + /* Generate code to handle the case of A==B
|
| + */
|
| + if( op==TK_ALL ){
|
| + addrAeqB = addrAltB;
|
| + }else if( op==TK_INTERSECT ){
|
| + addrAeqB = addrAltB;
|
| + addrAltB++;
|
| + }else{
|
| + VdbeNoopComment((v, "A-eq-B subroutine"));
|
| + addrAeqB =
|
| + sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA); VdbeCoverage(v);
|
| + sqlite3VdbeGoto(v, labelCmpr);
|
| + }
|
| +
|
| + /* Generate code to handle the case of A>B
|
| + */
|
| + VdbeNoopComment((v, "A-gt-B subroutine"));
|
| + addrAgtB = sqlite3VdbeCurrentAddr(v);
|
| + if( op==TK_ALL || op==TK_UNION ){
|
| + sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
|
| + sqlite3VdbeGoto(v, labelCmpr);
|
| +
|
| + /* This code runs once to initialize everything.
|
| + */
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v);
|
| + sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
|
| +
|
| + /* Implement the main merge loop
|
| + */
|
| + sqlite3VdbeResolveLabel(v, labelCmpr);
|
| + sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY);
|
| + sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
|
| + (char*)pKeyMerge, P4_KEYINFO);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
|
| + sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v);
|
| +
|
| + /* Jump to the this point in order to terminate the query.
|
| + */
|
| + sqlite3VdbeResolveLabel(v, labelEnd);
|
| +
|
| + /* Set the number of output columns
|
| + */
|
| + if( pDest->eDest==SRT_Output ){
|
| + Select *pFirst = pPrior;
|
| + while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
| + generateColumnNames(pParse, pFirst->pSrc, 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;
|
| + pPrior->pNext = p;
|
| +
|
| + /*** TBD: Insert subroutine calls to close cursors on incomplete
|
| + **** subqueries ****/
|
| + explainComposite(pParse, p->op, iSub1, iSub2, 0);
|
| + return pParse->nErr!=0;
|
| +}
|
| +#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*, int);
|
| +
|
| +/*
|
| +** 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 Expr *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 */
|
| +){
|
| + if( pExpr==0 ) return 0;
|
| + if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
|
| + if( pExpr->iColumn<0 ){
|
| + pExpr->op = TK_NULL;
|
| + }else{
|
| + Expr *pNew;
|
| + assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
|
| + assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
| + pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
|
| + sqlite3ExprDelete(db, pExpr);
|
| + pExpr = pNew;
|
| + }
|
| + }else{
|
| + pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
|
| + pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
|
| + if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
| + substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
|
| + }else{
|
| + substExprList(db, pExpr->x.pList, iTable, pEList);
|
| + }
|
| + }
|
| + return pExpr;
|
| +}
|
| +static void substExprList(
|
| + sqlite3 *db, /* Report malloc errors here */
|
| + ExprList *pList, /* List to scan and in which to make substitutes */
|
| + int iTable, /* Table to be substituted */
|
| + ExprList *pEList /* Substitute values */
|
| +){
|
| + int i;
|
| + if( pList==0 ) return;
|
| + for(i=0; i<pList->nExpr; i++){
|
| + pList->a[i].pExpr = substExpr(db, pList->a[i].pExpr, iTable, pEList);
|
| + }
|
| +}
|
| +static void substSelect(
|
| + sqlite3 *db, /* Report malloc errors here */
|
| + Select *p, /* SELECT statement in which to make substitutions */
|
| + int iTable, /* Table to be replaced */
|
| + ExprList *pEList, /* Substitute values */
|
| + int doPrior /* Do substitutes on p->pPrior too */
|
| +){
|
| + SrcList *pSrc;
|
| + struct SrcList_item *pItem;
|
| + int i;
|
| + if( !p ) return;
|
| + do{
|
| + substExprList(db, p->pEList, iTable, pEList);
|
| + substExprList(db, p->pGroupBy, iTable, pEList);
|
| + substExprList(db, p->pOrderBy, iTable, pEList);
|
| + p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
|
| + p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
|
| + pSrc = p->pSrc;
|
| + assert( pSrc!=0 );
|
| + for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
| + substSelect(db, pItem->pSelect, iTable, pEList, 1);
|
| + if( pItem->fg.isTabFunc ){
|
| + substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
|
| + }
|
| + }
|
| + }while( doPrior && (p = p->pPrior)!=0 );
|
| +}
|
| +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
| +
|
| +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
| +/*
|
| +** This routine attempts to flatten subqueries as a performance optimization.
|
| +** This routine returns 1 if it makes changes and 0 if no flattening occurs.
|
| +**
|
| +** To understand the concept of flattening, consider the following
|
| +** query:
|
| +**
|
| +** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5
|
| +**
|
| +** The default way of implementing this query is to execute the
|
| +** subquery first and store the results in a temporary table, then
|
| +** run the outer query on that temporary table. This requires two
|
| +** passes over the data. Furthermore, because the temporary table
|
| +** has no indices, the WHERE clause on the outer query cannot be
|
| +** optimized.
|
| +**
|
| +** This routine attempts to rewrite queries such as the above into
|
| +** a single flat select, like this:
|
| +**
|
| +** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
|
| +**
|
| +** The code generated for this simplification gives the same result
|
| +** but only has to scan the data once. And because indices might
|
| +** exist on the table t1, a complete scan of the data might be
|
| +** avoided.
|
| +**
|
| +** Flattening is only attempted if all of the following are true:
|
| +**
|
| +** (1) The subquery and the outer query do not both use aggregates.
|
| +**
|
| +** (2) The subquery is not an aggregate or (2a) the outer query is not a join
|
| +** and (2b) the outer query does not use subqueries other than the one
|
| +** FROM-clause subquery that is a candidate for flattening. (2b is
|
| +** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
|
| +**
|
| +** (3) The subquery is not the right operand of a left outer join
|
| +** (Originally ticket #306. Strengthened by ticket #3300)
|
| +**
|
| +** (4) The subquery is not DISTINCT.
|
| +**
|
| +** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT
|
| +** sub-queries that were excluded from this optimization. Restriction
|
| +** (4) has since been expanded to exclude all DISTINCT subqueries.
|
| +**
|
| +** (6) The subquery does not use aggregates or the outer query is not
|
| +** DISTINCT.
|
| +**
|
| +** (7) The subquery has a FROM clause. TODO: For subqueries without
|
| +** A FROM clause, consider adding a FROM close with the special
|
| +** table sqlite_once that consists of a single row containing a
|
| +** single NULL.
|
| +**
|
| +** (8) The subquery does not use LIMIT or the outer query is not a join.
|
| +**
|
| +** (9) The subquery does not use LIMIT or the outer query does not use
|
| +** aggregates.
|
| +**
|
| +** (**) Restriction (10) was removed from the code on 2005-02-05 but we
|
| +** accidently carried the comment forward until 2014-09-15. Original
|
| +** text: "The subquery does not use aggregates or the outer query
|
| +** does not use LIMIT."
|
| +**
|
| +** (11) The subquery and the outer query do not both have ORDER BY clauses.
|
| +**
|
| +** (**) Not implemented. Subsumed into restriction (3). Was previously
|
| +** a separate restriction deriving from ticket #350.
|
| +**
|
| +** (13) The subquery and outer query do not both use LIMIT.
|
| +**
|
| +** (14) The subquery does not use OFFSET.
|
| +**
|
| +** (15) The outer query is not part of a compound select or the
|
| +** subquery does not have a LIMIT clause.
|
| +** (See ticket #2339 and ticket [02a8e81d44]).
|
| +**
|
| +** (16) The outer query is not an aggregate or the subquery does
|
| +** not contain ORDER BY. (Ticket #2942) This used to not matter
|
| +** until we introduced the group_concat() function.
|
| +**
|
| +** (17) The sub-query is not a compound select, or it is a UNION ALL
|
| +** compound clause made up entirely of non-aggregate queries, and
|
| +** the parent query:
|
| +**
|
| +** * is not itself part of a compound select,
|
| +** * is not an aggregate or DISTINCT query, and
|
| +** * is not a join
|
| +**
|
| +** The parent and sub-query may contain WHERE clauses. Subject to
|
| +** rules (11), (13) and (14), they may also contain ORDER BY,
|
| +** LIMIT and OFFSET clauses. The subquery cannot use any compound
|
| +** operator other than UNION ALL because all the other compound
|
| +** operators have an implied DISTINCT which is disallowed by
|
| +** restriction (4).
|
| +**
|
| +** Also, each component of the sub-query must return the same number
|
| +** of result columns. This is actually a requirement for any compound
|
| +** SELECT statement, but all the code here does is make sure that no
|
| +** such (illegal) sub-query is flattened. The caller will detect the
|
| +** syntax error and return a detailed message.
|
| +**
|
| +** (18) If the sub-query is a compound select, then all terms of the
|
| +** ORDER by clause of the parent must be simple references to
|
| +** columns of the sub-query.
|
| +**
|
| +** (19) The subquery does not use LIMIT or the outer query does not
|
| +** have a WHERE clause.
|
| +**
|
| +** (20) If the sub-query is a compound select, then it must not use
|
| +** an ORDER BY clause. Ticket #3773. We could relax this constraint
|
| +** somewhat by saying that the terms of the ORDER BY clause must
|
| +** appear as unmodified result columns in the outer query. But we
|
| +** have other optimizations in mind to deal with that case.
|
| +**
|
| +** (21) The subquery does not use LIMIT or the outer query is not
|
| +** DISTINCT. (See ticket [752e1646fc]).
|
| +**
|
| +** (22) The subquery is not a recursive CTE.
|
| +**
|
| +** (23) The parent is not a recursive CTE, or the sub-query is not a
|
| +** compound query. This restriction is because transforming the
|
| +** parent to a compound query confuses the code that handles
|
| +** recursive queries in multiSelect().
|
| +**
|
| +** (24) The subquery is not an aggregate that uses the built-in min() or
|
| +** or max() functions. (Without this restriction, a query like:
|
| +** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
|
| +** return the value X for which Y was maximal.)
|
| +**
|
| +**
|
| +** In this routine, the "p" parameter is a pointer to the outer query.
|
| +** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
|
| +** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
|
| +**
|
| +** If flattening is not attempted, this routine is a no-op and returns 0.
|
| +** If flattening is attempted this routine returns 1.
|
| +**
|
| +** All of the expression analysis must occur on both the outer query and
|
| +** the subquery before this routine runs.
|
| +*/
|
| +static int flattenSubquery(
|
| + Parse *pParse, /* Parsing context */
|
| + Select *p, /* The parent or outer SELECT statement */
|
| + int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
|
| + 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; /* Current UNION ALL term of the other query */
|
| + 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.
|
| + */
|
| + assert( p!=0 );
|
| + assert( p->pPrior==0 ); /* Unable to flatten compound queries */
|
| + if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
|
| + pSrc = p->pSrc;
|
| + assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
|
| + pSubitem = &pSrc->a[iFrom];
|
| + iParent = pSubitem->iCursor;
|
| + pSub = pSubitem->pSelect;
|
| + assert( pSub!=0 );
|
| + if( subqueryIsAgg ){
|
| + if( isAgg ) return 0; /* Restriction (1) */
|
| + if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */
|
| + if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
|
| + || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
|
| + || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
|
| + ){
|
| + return 0; /* Restriction (2b) */
|
| + }
|
| + }
|
| +
|
| + pSubSrc = pSub->pSrc;
|
| + assert( pSubSrc );
|
| + /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
|
| + ** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET
|
| + ** because they could be computed at compile-time. But when LIMIT and OFFSET
|
| + ** became arbitrary expressions, we were forced to add restrictions (13)
|
| + ** and (14). */
|
| + if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
|
| + if( pSub->pOffset ) return 0; /* Restriction (14) */
|
| + if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){
|
| + return 0; /* Restriction (15) */
|
| + }
|
| + if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
|
| + if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */
|
| + if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){
|
| + return 0; /* Restrictions (8)(9) */
|
| + }
|
| + if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){
|
| + return 0; /* Restriction (6) */
|
| + }
|
| + if( p->pOrderBy && pSub->pOrderBy ){
|
| + return 0; /* Restriction (11) */
|
| + }
|
| + if( isAgg && pSub->pOrderBy ) return 0; /* Restriction (16) */
|
| + if( pSub->pLimit && p->pWhere ) return 0; /* Restriction (19) */
|
| + if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
|
| + return 0; /* Restriction (21) */
|
| + }
|
| + testcase( pSub->selFlags & SF_Recursive );
|
| + testcase( pSub->selFlags & SF_MinMaxAgg );
|
| + if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
|
| + return 0; /* Restrictions (22) and (24) */
|
| + }
|
| + if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
|
| + return 0; /* Restriction (23) */
|
| + }
|
| +
|
| + /* OBSOLETE COMMENT 1:
|
| + ** Restriction 3: If the subquery is a join, make sure the subquery is
|
| + ** not used as the right operand of an outer join. Examples of why this
|
| + ** is not allowed:
|
| + **
|
| + ** t1 LEFT OUTER JOIN (t2 JOIN t3)
|
| + **
|
| + ** If we flatten the above, we would get
|
| + **
|
| + ** (t1 LEFT OUTER JOIN t2) JOIN t3
|
| + **
|
| + ** which is not at all the same thing.
|
| + **
|
| + ** OBSOLETE COMMENT 2:
|
| + ** Restriction 12: If the subquery is the right operand of a left outer
|
| + ** join, make sure the subquery has no WHERE clause.
|
| + ** An examples of why this is not allowed:
|
| + **
|
| + ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
|
| + **
|
| + ** If we flatten the above, we would get
|
| + **
|
| + ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
|
| + **
|
| + ** But the t2.x>0 test will always fail on a NULL row of t2, which
|
| + ** effectively converts the OUTER JOIN into an INNER JOIN.
|
| + **
|
| + ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE:
|
| + ** Ticket #3300 shows that flattening the right term of a LEFT JOIN
|
| + ** is fraught with danger. Best to avoid the whole thing. If the
|
| + ** subquery is the right term of a LEFT JOIN, then do not flatten.
|
| + */
|
| + if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
|
| + return 0;
|
| + }
|
| +
|
| + /* Restriction 17: If the sub-query is a compound SELECT, then it must
|
| + ** use only the UNION ALL operator. And none of the simple select queries
|
| + ** that make up the compound SELECT are allowed to be aggregate or distinct
|
| + ** queries.
|
| + */
|
| + if( pSub->pPrior ){
|
| + if( pSub->pOrderBy ){
|
| + return 0; /* Restriction 20 */
|
| + }
|
| + if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
|
| + return 0;
|
| + }
|
| + for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
|
| + testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
|
| + testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
|
| + assert( pSub->pSrc!=0 );
|
| + assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
|
| + if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
|
| + || (pSub1->pPrior && pSub1->op!=TK_ALL)
|
| + || pSub1->pSrc->nSrc<1
|
| + ){
|
| + return 0;
|
| + }
|
| + testcase( pSub1->pSrc->nSrc>1 );
|
| + }
|
| +
|
| + /* Restriction 18. */
|
| + if( p->pOrderBy ){
|
| + int ii;
|
| + for(ii=0; ii<p->pOrderBy->nExpr; ii++){
|
| + if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /***** If we reach this point, flattening is permitted. *****/
|
| + SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
|
| + pSub->zSelName, pSub, iFrom));
|
| +
|
| + /* Authorize the subquery */
|
| + pParse->zAuthContext = pSubitem->zName;
|
| + TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0);
|
| + testcase( i==SQLITE_DENY );
|
| + pParse->zAuthContext = zSavedAuthContext;
|
| +
|
| + /* If the sub-query is a compound SELECT statement, then (by restrictions
|
| + ** 17 and 18 above) it must be a UNION ALL and the parent query must
|
| + ** be of the form:
|
| + **
|
| + ** SELECT <expr-list> FROM (<sub-query>) <where-clause>
|
| + **
|
| + ** followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block
|
| + ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or
|
| + ** OFFSET clauses and joins them to the left-hand-side of the original
|
| + ** using UNION ALL operators. In this case N is the number of simple
|
| + ** select statements in the compound sub-query.
|
| + **
|
| + ** Example:
|
| + **
|
| + ** SELECT a+1 FROM (
|
| + ** SELECT x FROM tab
|
| + ** UNION ALL
|
| + ** SELECT y FROM tab
|
| + ** UNION ALL
|
| + ** SELECT abs(z*2) FROM tab2
|
| + ** ) WHERE a!=5 ORDER BY 1
|
| + **
|
| + ** Transformed into:
|
| + **
|
| + ** SELECT x+1 FROM tab WHERE x+1!=5
|
| + ** UNION ALL
|
| + ** SELECT y+1 FROM tab WHERE y+1!=5
|
| + ** UNION ALL
|
| + ** SELECT abs(z*2)+1 FROM tab2 WHERE abs(z*2)+1!=5
|
| + ** ORDER BY 1
|
| + **
|
| + ** We call this the "compound-subquery flattening".
|
| + */
|
| + for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){
|
| + Select *pNew;
|
| + ExprList *pOrderBy = p->pOrderBy;
|
| + Expr *pLimit = p->pLimit;
|
| + Expr *pOffset = p->pOffset;
|
| + Select *pPrior = p->pPrior;
|
| + p->pOrderBy = 0;
|
| + p->pSrc = 0;
|
| + p->pPrior = 0;
|
| + p->pLimit = 0;
|
| + p->pOffset = 0;
|
| + pNew = sqlite3SelectDup(db, p, 0);
|
| + sqlite3SelectSetName(pNew, pSub->zSelName);
|
| + p->pOffset = pOffset;
|
| + p->pLimit = pLimit;
|
| + p->pOrderBy = pOrderBy;
|
| + p->pSrc = pSrc;
|
| + p->op = TK_ALL;
|
| + if( pNew==0 ){
|
| + p->pPrior = pPrior;
|
| + }else{
|
| + pNew->pPrior = pPrior;
|
| + if( pPrior ) pPrior->pNext = pNew;
|
| + pNew->pNext = p;
|
| + p->pPrior = pNew;
|
| + SELECTTRACE(2,pParse,p,
|
| + ("compound-subquery flattener creates %s.%p as peer\n",
|
| + pNew->zSelName, pNew));
|
| + }
|
| + if( db->mallocFailed ) return 1;
|
| + }
|
| +
|
| + /* Begin flattening the iFrom-th entry of the FROM clause
|
| + ** in the outer query.
|
| + */
|
| + pSub = pSub1 = pSubitem->pSelect;
|
| +
|
| + /* Delete the transient table structure associated with the
|
| + ** subquery
|
| + */
|
| + sqlite3DbFree(db, pSubitem->zDatabase);
|
| + sqlite3DbFree(db, pSubitem->zName);
|
| + sqlite3DbFree(db, pSubitem->zAlias);
|
| + pSubitem->zDatabase = 0;
|
| + pSubitem->zName = 0;
|
| + pSubitem->zAlias = 0;
|
| + pSubitem->pSelect = 0;
|
| +
|
| + /* Defer deleting the Table object associated with the
|
| + ** subquery until code generation is
|
| + ** complete, since there may still exist Expr.pTab entries that
|
| + ** refer to the subquery even after flattening. Ticket #3346.
|
| + **
|
| + ** pSubitem->pTab is always non-NULL by test restrictions and tests above.
|
| + */
|
| + if( ALWAYS(pSubitem->pTab!=0) ){
|
| + Table *pTabToDel = pSubitem->pTab;
|
| + if( pTabToDel->nRef==1 ){
|
| + Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + pTabToDel->pNextZombie = pToplevel->pZombieTab;
|
| + pToplevel->pZombieTab = pTabToDel;
|
| + }else{
|
| + pTabToDel->nRef--;
|
| + }
|
| + pSubitem->pTab = 0;
|
| + }
|
| +
|
| + /* The following loop runs once for each term in a compound-subquery
|
| + ** flattening (as described above). If we are doing a different kind
|
| + ** of flattening - a flattening other than a compound-subquery flattening -
|
| + ** then this loop only runs once.
|
| + **
|
| + ** This loop moves 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.
|
| + */
|
| + for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){
|
| + int nSubSrc;
|
| + u8 jointype = 0;
|
| + pSubSrc = pSub->pSrc; /* FROM clause of subquery */
|
| + nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */
|
| + pSrc = pParent->pSrc; /* FROM clause of the outer query */
|
| +
|
| + if( pSrc ){
|
| + assert( pParent==p ); /* First time through the loop */
|
| + jointype = pSubitem->fg.jointype;
|
| + }else{
|
| + assert( pParent!=p ); /* 2nd and subsequent times through the loop */
|
| + pSrc = pParent->pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
|
| + if( pSrc==0 ){
|
| + assert( db->mallocFailed );
|
| + break;
|
| + }
|
| + }
|
| +
|
| + /* The subquery uses a single slot of the FROM clause of the outer
|
| + ** query. If the subquery has more than one element in its FROM clause,
|
| + ** then expand the outer query to make space for it to hold all elements
|
| + ** of the subquery.
|
| + **
|
| + ** Example:
|
| + **
|
| + ** SELECT * FROM tabA, (SELECT * FROM sub1, sub2), tabB;
|
| + **
|
| + ** The outer query has 3 slots in its FROM clause. One slot of the
|
| + ** outer query (the middle slot) is used by the subquery. The next
|
| + ** block of code will expand the outer query FROM clause to 4 slots.
|
| + ** The middle slot is expanded to two slots in order to make space
|
| + ** for the two elements in the FROM clause of the subquery.
|
| + */
|
| + if( nSubSrc>1 ){
|
| + pParent->pSrc = pSrc = sqlite3SrcListEnlarge(db, pSrc, nSubSrc-1,iFrom+1);
|
| + if( db->mallocFailed ){
|
| + break;
|
| + }
|
| + }
|
| +
|
| + /* Transfer the FROM clause terms from the subquery into the
|
| + ** outer query.
|
| + */
|
| + for(i=0; i<nSubSrc; i++){
|
| + sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
|
| + assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
|
| + pSrc->a[i+iFrom] = pSubSrc->a[i];
|
| + memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
|
| + }
|
| + pSrc->a[iFrom].fg.jointype = jointype;
|
| +
|
| + /* Now begin substituting subquery result set expressions for
|
| + ** references to the iParent in the outer query.
|
| + **
|
| + ** Example:
|
| + **
|
| + ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
|
| + ** \ \_____________ subquery __________/ /
|
| + ** \_____________________ outer query ______________________________/
|
| + **
|
| + ** We look at every expression in the outer query and every place we see
|
| + ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
|
| + */
|
| + pList = pParent->pEList;
|
| + for(i=0; i<pList->nExpr; i++){
|
| + if( pList->a[i].zName==0 ){
|
| + char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan);
|
| + sqlite3Dequote(zName);
|
| + pList->a[i].zName = zName;
|
| + }
|
| + }
|
| + if( pSub->pOrderBy ){
|
| + /* At this point, any non-zero iOrderByCol values indicate that the
|
| + ** ORDER BY column expression is identical to the iOrderByCol'th
|
| + ** expression returned by SELECT statement pSub. Since these values
|
| + ** do not necessarily correspond to columns in SELECT statement pParent,
|
| + ** zero them before transfering the ORDER BY clause.
|
| + **
|
| + ** Not doing this may cause an error if a subsequent call to this
|
| + ** function attempts to flatten a compound sub-query into pParent
|
| + ** (the only way this can happen is if the compound sub-query is
|
| + ** currently part of pSub->pSrc). See ticket [d11a6e908f]. */
|
| + ExprList *pOrderBy = pSub->pOrderBy;
|
| + for(i=0; i<pOrderBy->nExpr; i++){
|
| + pOrderBy->a[i].u.x.iOrderByCol = 0;
|
| + }
|
| + assert( pParent->pOrderBy==0 );
|
| + assert( pSub->pPrior==0 );
|
| + pParent->pOrderBy = pOrderBy;
|
| + pSub->pOrderBy = 0;
|
| + }
|
| + pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
|
| + if( subqueryIsAgg ){
|
| + assert( pParent->pHaving==0 );
|
| + pParent->pHaving = pParent->pWhere;
|
| + pParent->pWhere = pWhere;
|
| + pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
|
| + sqlite3ExprDup(db, pSub->pHaving, 0));
|
| + assert( pParent->pGroupBy==0 );
|
| + pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
|
| + }else{
|
| + pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
|
| + }
|
| + substSelect(db, pParent, iParent, pSub->pEList, 0);
|
| +
|
| + /* The flattened query is distinct if either the inner or the
|
| + ** outer query is distinct.
|
| + */
|
| + pParent->selFlags |= pSub->selFlags & SF_Distinct;
|
| +
|
| + /*
|
| + ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
|
| + **
|
| + ** One is tempted to try to add a and b to combine the limits. But this
|
| + ** does not work if either limit is negative.
|
| + */
|
| + if( pSub->pLimit ){
|
| + pParent->pLimit = pSub->pLimit;
|
| + pSub->pLimit = 0;
|
| + }
|
| + }
|
| +
|
| + /* Finially, delete what is left of the subquery and return
|
| + ** success.
|
| + */
|
| + sqlite3SelectDelete(db, pSub1);
|
| +
|
| +#if SELECTTRACE_ENABLED
|
| + if( sqlite3SelectTrace & 0x100 ){
|
| + SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
|
| + sqlite3TreeViewSelect(0, p, 0);
|
| + }
|
| +#endif
|
| +
|
| + return 1;
|
| +}
|
| +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
| +
|
| +
|
| +
|
| +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
| +/*
|
| +** Make copies of relevant WHERE clause terms of the outer query into
|
| +** the WHERE clause of subquery. Example:
|
| +**
|
| +** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10;
|
| +**
|
| +** Transformed into:
|
| +**
|
| +** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10)
|
| +** WHERE x=5 AND y=10;
|
| +**
|
| +** The hope is that the terms added to the inner query will make it more
|
| +** efficient.
|
| +**
|
| +** Do not attempt this optimization if:
|
| +**
|
| +** (1) The inner query is an aggregate. (In that case, we'd really want
|
| +** to copy the outer WHERE-clause terms onto the HAVING clause of the
|
| +** inner query. But they probably won't help there so do not bother.)
|
| +**
|
| +** (2) The inner query is the recursive part of a common table expression.
|
| +**
|
| +** (3) The inner query has a LIMIT clause (since the changes to the WHERE
|
| +** close would change the meaning of the LIMIT).
|
| +**
|
| +** (4) The inner query is the right operand of a LEFT JOIN. (The caller
|
| +** enforces this restriction since this routine does not have enough
|
| +** information to know.)
|
| +**
|
| +** (5) The WHERE clause expression originates in the ON or USING clause
|
| +** of a LEFT JOIN.
|
| +**
|
| +** Return 0 if no changes are made and non-zero if one or more WHERE clause
|
| +** terms are duplicated into the subquery.
|
| +*/
|
| +static int pushDownWhereTerms(
|
| + sqlite3 *db, /* The database connection (for malloc()) */
|
| + Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
|
| + Expr *pWhere, /* The WHERE clause of the outer query */
|
| + int iCursor /* Cursor number of the subquery */
|
| +){
|
| + Expr *pNew;
|
| + int nChng = 0;
|
| + if( pWhere==0 ) return 0;
|
| + if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
|
| + return 0; /* restrictions (1) and (2) */
|
| + }
|
| + if( pSubq->pLimit!=0 ){
|
| + return 0; /* restriction (3) */
|
| + }
|
| + while( pWhere->op==TK_AND ){
|
| + nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
|
| + pWhere = pWhere->pLeft;
|
| + }
|
| + if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
|
| + if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
| + nChng++;
|
| + while( pSubq ){
|
| + pNew = sqlite3ExprDup(db, pWhere, 0);
|
| + pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
|
| + pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
|
| + pSubq = pSubq->pPrior;
|
| + }
|
| + }
|
| + return nChng;
|
| +}
|
| +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
| +
|
| +/*
|
| +** Based on the contents of the AggInfo structure indicated by the first
|
| +** argument, this function checks if the following are true:
|
| +**
|
| +** * the query contains just a single aggregate function,
|
| +** * the aggregate function is either min() or max(), and
|
| +** * the argument to the aggregate function is a column value.
|
| +**
|
| +** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX
|
| +** is returned as appropriate. Also, *ppMinMax is set to point to the
|
| +** list of arguments passed to the aggregate before returning.
|
| +**
|
| +** Or, if the conditions above are not met, *ppMinMax is set to 0 and
|
| +** WHERE_ORDERBY_NORMAL is returned.
|
| +*/
|
| +static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
|
| + int eRet = WHERE_ORDERBY_NORMAL; /* Return value */
|
| +
|
| + *ppMinMax = 0;
|
| + if( pAggInfo->nFunc==1 ){
|
| + Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */
|
| + ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */
|
| +
|
| + assert( pExpr->op==TK_AGG_FUNCTION );
|
| + if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){
|
| + const char *zFunc = pExpr->u.zToken;
|
| + if( sqlite3StrICmp(zFunc, "min")==0 ){
|
| + eRet = WHERE_ORDERBY_MIN;
|
| + *ppMinMax = pEList;
|
| + }else if( sqlite3StrICmp(zFunc, "max")==0 ){
|
| + eRet = WHERE_ORDERBY_MAX;
|
| + *ppMinMax = pEList;
|
| + }
|
| + }
|
| + }
|
| +
|
| + assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 );
|
| + return eRet;
|
| +}
|
| +
|
| +/*
|
| +** The select statement passed as the first argument is an aggregate query.
|
| +** The second argument is the associated aggregate-info object. This
|
| +** function tests if the SELECT is of the form:
|
| +**
|
| +** SELECT count(*) FROM <tbl>
|
| +**
|
| +** where table is a database table, not a sub-select or view. If the query
|
| +** does match this pattern, then a pointer to the Table object representing
|
| +** <tbl> is returned. Otherwise, 0 is returned.
|
| +*/
|
| +static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
| + Table *pTab;
|
| + Expr *pExpr;
|
| +
|
| + assert( !p->pGroupBy );
|
| +
|
| + if( p->pWhere || p->pEList->nExpr!=1
|
| + || p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect
|
| + ){
|
| + return 0;
|
| + }
|
| + pTab = p->pSrc->a[0].pTab;
|
| + pExpr = p->pEList->a[0].pExpr;
|
| + assert( pTab && !pTab->pSelect && pExpr );
|
| +
|
| + if( IsVirtual(pTab) ) return 0;
|
| + if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
|
| + if( NEVER(pAggInfo->nFunc==0) ) return 0;
|
| + if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0;
|
| + if( pExpr->flags&EP_Distinct ) return 0;
|
| +
|
| + return pTab;
|
| +}
|
| +
|
| +/*
|
| +** If the source-list item passed as an argument was augmented with an
|
| +** INDEXED BY clause, then try to locate the specified index. If there
|
| +** was such a clause and the named index cannot be found, return
|
| +** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
|
| +** pFrom->pIndex and return SQLITE_OK.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
|
| + if( pFrom->pTab && pFrom->fg.isIndexedBy ){
|
| + Table *pTab = pFrom->pTab;
|
| + char *zIndexedBy = pFrom->u1.zIndexedBy;
|
| + Index *pIdx;
|
| + for(pIdx=pTab->pIndex;
|
| + pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
|
| + pIdx=pIdx->pNext
|
| + );
|
| + if( !pIdx ){
|
| + sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0);
|
| + pParse->checkSchema = 1;
|
| + return SQLITE_ERROR;
|
| + }
|
| + pFrom->pIBIndex = pIdx;
|
| + }
|
| + return SQLITE_OK;
|
| +}
|
| +/*
|
| +** Detect compound SELECT statements that use an ORDER BY clause with
|
| +** an alternative collating sequence.
|
| +**
|
| +** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ...
|
| +**
|
| +** These are rewritten as a subquery:
|
| +**
|
| +** SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2)
|
| +** ORDER BY ... COLLATE ...
|
| +**
|
| +** This transformation is necessary because the multiSelectOrderBy() routine
|
| +** above that generates the code for a compound SELECT with an ORDER BY clause
|
| +** uses a merge algorithm that requires the same collating sequence on the
|
| +** result columns as on the ORDER BY clause. See ticket
|
| +** http://www.sqlite.org/src/info/6709574d2a
|
| +**
|
| +** This transformation is only needed for EXCEPT, INTERSECT, and UNION.
|
| +** The UNION ALL operator works fine with multiSelectOrderBy() even when
|
| +** there are COLLATE terms in the ORDER BY.
|
| +*/
|
| +static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
| + int i;
|
| + Select *pNew;
|
| + Select *pX;
|
| + sqlite3 *db;
|
| + struct ExprList_item *a;
|
| + SrcList *pNewSrc;
|
| + Parse *pParse;
|
| + Token dummy;
|
| +
|
| + if( p->pPrior==0 ) return WRC_Continue;
|
| + if( p->pOrderBy==0 ) return WRC_Continue;
|
| + for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){}
|
| + if( pX==0 ) return WRC_Continue;
|
| + a = p->pOrderBy->a;
|
| + for(i=p->pOrderBy->nExpr-1; i>=0; i--){
|
| + if( a[i].pExpr->flags & EP_Collate ) break;
|
| + }
|
| + if( i<0 ) return WRC_Continue;
|
| +
|
| + /* If we reach this point, that means the transformation is required. */
|
| +
|
| + pParse = pWalker->pParse;
|
| + db = pParse->db;
|
| + pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
|
| + if( pNew==0 ) return WRC_Abort;
|
| + memset(&dummy, 0, sizeof(dummy));
|
| + pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0);
|
| + if( pNewSrc==0 ) return WRC_Abort;
|
| + *pNew = *p;
|
| + p->pSrc = pNewSrc;
|
| + p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
|
| + p->op = TK_SELECT;
|
| + p->pWhere = 0;
|
| + pNew->pGroupBy = 0;
|
| + pNew->pHaving = 0;
|
| + pNew->pOrderBy = 0;
|
| + p->pPrior = 0;
|
| + p->pNext = 0;
|
| + p->pWith = 0;
|
| + p->selFlags &= ~SF_Compound;
|
| + assert( (p->selFlags & SF_Converted)==0 );
|
| + p->selFlags |= SF_Converted;
|
| + assert( pNew->pPrior!=0 );
|
| + pNew->pPrior->pNext = pNew;
|
| + pNew->pLimit = 0;
|
| + pNew->pOffset = 0;
|
| + return WRC_Continue;
|
| +}
|
| +
|
| +/*
|
| +** Check to see if the FROM clause term pFrom has table-valued function
|
| +** arguments. If it does, leave an error message in pParse and return
|
| +** non-zero, since pFrom is not allowed to be a table-valued function.
|
| +*/
|
| +static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
|
| + if( pFrom->fg.isTabFunc ){
|
| + sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName);
|
| + return 1;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_CTE
|
| +/*
|
| +** Argument pWith (which may be NULL) points to a linked list of nested
|
| +** WITH contexts, from inner to outermost. If the table identified by
|
| +** FROM clause element pItem is really a common-table-expression (CTE)
|
| +** then return a pointer to the CTE definition for that table. Otherwise
|
| +** return NULL.
|
| +**
|
| +** If a non-NULL value is returned, set *ppContext to point to the With
|
| +** object that the returned CTE belongs to.
|
| +*/
|
| +static struct Cte *searchWith(
|
| + With *pWith, /* Current innermost WITH clause */
|
| + struct SrcList_item *pItem, /* FROM clause element to resolve */
|
| + With **ppContext /* OUT: WITH clause return value belongs to */
|
| +){
|
| + const char *zName;
|
| + if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){
|
| + With *p;
|
| + for(p=pWith; p; p=p->pOuter){
|
| + int i;
|
| + for(i=0; i<p->nCte; i++){
|
| + if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
|
| + *ppContext = p;
|
| + return &p->a[i];
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/* The code generator maintains a stack of active WITH clauses
|
| +** with the inner-most WITH clause being at the top of the stack.
|
| +**
|
| +** This routine pushes the WITH clause passed as the second argument
|
| +** onto the top of the stack. If argument bFree is true, then this
|
| +** WITH clause will never be popped from the stack. In this case it
|
| +** should be freed along with the Parse object. In other cases, when
|
| +** bFree==0, the With object will be freed along with the SELECT
|
| +** statement with which it is associated.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
|
| + assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) );
|
| + if( pWith ){
|
| + assert( pParse->pWith!=pWith );
|
| + pWith->pOuter = pParse->pWith;
|
| + pParse->pWith = pWith;
|
| + if( bFree ) pParse->pWithToFree = pWith;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This function checks if argument pFrom refers to a CTE declared by
|
| +** a WITH clause on the stack currently maintained by the parser. And,
|
| +** if currently processing a CTE expression, if it is a recursive
|
| +** reference to the current CTE.
|
| +**
|
| +** If pFrom falls into either of the two categories above, pFrom->pTab
|
| +** and other fields are populated accordingly. The caller should check
|
| +** (pFrom->pTab!=0) to determine whether or not a successful match
|
| +** was found.
|
| +**
|
| +** Whether or not a match is found, SQLITE_OK is returned if no error
|
| +** occurs. If an error does occur, an error message is stored in the
|
| +** parser and some error code other than SQLITE_OK returned.
|
| +*/
|
| +static int withExpand(
|
| + Walker *pWalker,
|
| + struct SrcList_item *pFrom
|
| +){
|
| + Parse *pParse = pWalker->pParse;
|
| + sqlite3 *db = pParse->db;
|
| + struct Cte *pCte; /* Matched CTE (or NULL if no match) */
|
| + With *pWith; /* WITH clause that pCte belongs to */
|
| +
|
| + assert( pFrom->pTab==0 );
|
| +
|
| + pCte = searchWith(pParse->pWith, pFrom, &pWith);
|
| + if( pCte ){
|
| + Table *pTab;
|
| + ExprList *pEList;
|
| + Select *pSel;
|
| + Select *pLeft; /* Left-most SELECT statement */
|
| + int bMayRecursive; /* True if compound joined by UNION [ALL] */
|
| + With *pSavedWith; /* Initial value of pParse->pWith */
|
| +
|
| + /* If pCte->zCteErr is non-NULL at this point, then this is an illegal
|
| + ** recursive reference to CTE pCte. Leave an error in pParse and return
|
| + ** early. If pCte->zCteErr is NULL, then this is not a recursive reference.
|
| + ** In this case, proceed. */
|
| + if( pCte->zCteErr ){
|
| + sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
|
| + return SQLITE_ERROR;
|
| + }
|
| + if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR;
|
| +
|
| + assert( pFrom->pTab==0 );
|
| + pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
| + if( pTab==0 ) return WRC_Abort;
|
| + pTab->nRef = 1;
|
| + pTab->zName = sqlite3DbStrDup(db, pCte->zName);
|
| + pTab->iPKey = -1;
|
| + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
| + pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
|
| + pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
|
| + if( db->mallocFailed ) return SQLITE_NOMEM;
|
| + assert( pFrom->pSelect );
|
| +
|
| + /* Check if this is a recursive CTE. */
|
| + pSel = pFrom->pSelect;
|
| + bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
|
| + if( bMayRecursive ){
|
| + int i;
|
| + SrcList *pSrc = pFrom->pSelect->pSrc;
|
| + for(i=0; i<pSrc->nSrc; i++){
|
| + struct SrcList_item *pItem = &pSrc->a[i];
|
| + if( pItem->zDatabase==0
|
| + && pItem->zName!=0
|
| + && 0==sqlite3StrICmp(pItem->zName, pCte->zName)
|
| + ){
|
| + pItem->pTab = pTab;
|
| + pItem->fg.isRecursive = 1;
|
| + pTab->nRef++;
|
| + pSel->selFlags |= SF_Recursive;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* Only one recursive reference is permitted. */
|
| + if( pTab->nRef>2 ){
|
| + sqlite3ErrorMsg(
|
| + pParse, "multiple references to recursive table: %s", pCte->zName
|
| + );
|
| + return SQLITE_ERROR;
|
| + }
|
| + assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
|
| +
|
| + pCte->zCteErr = "circular reference: %s";
|
| + pSavedWith = pParse->pWith;
|
| + pParse->pWith = pWith;
|
| + sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
|
| + pParse->pWith = pWith;
|
| +
|
| + for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
|
| + pEList = pLeft->pEList;
|
| + if( pCte->pCols ){
|
| + if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){
|
| + sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns",
|
| + pCte->zName, pEList->nExpr, pCte->pCols->nExpr
|
| + );
|
| + pParse->pWith = pSavedWith;
|
| + return SQLITE_ERROR;
|
| + }
|
| + pEList = pCte->pCols;
|
| + }
|
| +
|
| + sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
|
| + if( bMayRecursive ){
|
| + if( pSel->selFlags & SF_Recursive ){
|
| + pCte->zCteErr = "multiple recursive references: %s";
|
| + }else{
|
| + pCte->zCteErr = "recursive reference in a subquery: %s";
|
| + }
|
| + sqlite3WalkSelect(pWalker, pSel);
|
| + }
|
| + pCte->zCteErr = 0;
|
| + pParse->pWith = pSavedWith;
|
| + }
|
| +
|
| + return SQLITE_OK;
|
| +}
|
| +#endif
|
| +
|
| +#ifndef SQLITE_OMIT_CTE
|
| +/*
|
| +** If the SELECT passed as the second argument has an associated WITH
|
| +** clause, pop it from the stack stored as part of the Parse object.
|
| +**
|
| +** This function is used as the xSelectCallback2() callback by
|
| +** sqlite3SelectExpand() when walking a SELECT tree to resolve table
|
| +** names and other FROM clause elements.
|
| +*/
|
| +static void selectPopWith(Walker *pWalker, Select *p){
|
| + Parse *pParse = pWalker->pParse;
|
| + With *pWith = findRightmost(p)->pWith;
|
| + if( pWith!=0 ){
|
| + assert( pParse->pWith==pWith );
|
| + pParse->pWith = pWith->pOuter;
|
| + }
|
| +}
|
| +#else
|
| +#define selectPopWith 0
|
| +#endif
|
| +
|
| +/*
|
| +** This routine is a Walker callback for "expanding" a SELECT statement.
|
| +** "Expanding" means to do the following:
|
| +**
|
| +** (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 persistent representation
|
| +** of the view.
|
| +**
|
| +** (3) Add terms to the WHERE clause to accommodate the NATURAL keyword
|
| +** on joins and the ON and USING clause of joins.
|
| +**
|
| +** (4) Scan the list of columns in the result set (pEList) looking
|
| +** for instances of the "*" operator or the TABLE.* operator.
|
| +** If found, expand each "*" to be every column in every table
|
| +** and TABLE.* to be every column in TABLE.
|
| +**
|
| +*/
|
| +static int selectExpander(Walker *pWalker, Select *p){
|
| + Parse *pParse = pWalker->pParse;
|
| + int i, j, k;
|
| + SrcList *pTabList;
|
| + ExprList *pEList;
|
| + struct SrcList_item *pFrom;
|
| + sqlite3 *db = pParse->db;
|
| + Expr *pE, *pRight, *pExpr;
|
| + u16 selFlags = p->selFlags;
|
| +
|
| + p->selFlags |= SF_Expanded;
|
| + if( db->mallocFailed ){
|
| + return WRC_Abort;
|
| + }
|
| + if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
|
| + return WRC_Prune;
|
| + }
|
| + pTabList = p->pSrc;
|
| + pEList = p->pEList;
|
| + if( pWalker->xSelectCallback2==selectPopWith ){
|
| + sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
|
| + }
|
| +
|
| + /* Make sure cursor numbers have been assigned to all entries in
|
| + ** the FROM clause of the SELECT statement.
|
| + */
|
| + sqlite3SrcListAssignCursors(pParse, pTabList);
|
| +
|
| + /* 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;
|
| + assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
|
| + if( pFrom->fg.isRecursive ) continue;
|
| + assert( pFrom->pTab==0 );
|
| +#ifndef SQLITE_OMIT_CTE
|
| + if( withExpand(pWalker, pFrom) ) return WRC_Abort;
|
| + if( pFrom->pTab ) {} else
|
| +#endif
|
| + if( pFrom->zName==0 ){
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| + Select *pSel = pFrom->pSelect;
|
| + /* A sub-query in the FROM clause of a SELECT */
|
| + assert( pSel!=0 );
|
| + assert( pFrom->pTab==0 );
|
| + if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
|
| + pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
| + if( pTab==0 ) return WRC_Abort;
|
| + pTab->nRef = 1;
|
| + pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
|
| + while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
| + sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
|
| + pTab->iPKey = -1;
|
| + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
| + pTab->tabFlags |= TF_Ephemeral;
|
| +#endif
|
| + }else{
|
| + /* An ordinary table or view name in the FROM clause */
|
| + assert( pFrom->pTab==0 );
|
| + pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
|
| + if( pTab==0 ) return WRC_Abort;
|
| + if( pTab->nRef==0xffff ){
|
| + sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
|
| + pTab->zName);
|
| + pFrom->pTab = 0;
|
| + return WRC_Abort;
|
| + }
|
| + pTab->nRef++;
|
| + if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
|
| + return WRC_Abort;
|
| + }
|
| +#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
|
| + if( IsVirtual(pTab) || pTab->pSelect ){
|
| + i16 nCol;
|
| + if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
|
| + assert( pFrom->pSelect==0 );
|
| + pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
|
| + sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
|
| + nCol = pTab->nCol;
|
| + pTab->nCol = -1;
|
| + sqlite3WalkSelect(pWalker, pFrom->pSelect);
|
| + pTab->nCol = nCol;
|
| + }
|
| +#endif
|
| + }
|
| +
|
| + /* Locate the index named by the INDEXED BY clause, if any. */
|
| + if( sqlite3IndexedByLookup(pParse, pFrom) ){
|
| + return WRC_Abort;
|
| + }
|
| + }
|
| +
|
| + /* Process NATURAL keywords, and ON and USING clauses of joins.
|
| + */
|
| + if( db->mallocFailed || sqliteProcessJoin(pParse, p) ){
|
| + return WRC_Abort;
|
| + }
|
| +
|
| + /* For every "*" that occurs in the column list, insert the names of
|
| + ** all columns in all tables. And for every TABLE.* insert the names
|
| + ** of all columns in TABLE. The parser inserted a special expression
|
| + ** with the TK_ASTERISK operator for each "*" that it found in the column
|
| + ** list. The following code just has to locate the TK_ASTERISK
|
| + ** expressions and expand each one to the list of all columns in
|
| + ** all tables.
|
| + **
|
| + ** The first loop just checks to see if there are any "*" operators
|
| + ** that need expanding.
|
| + */
|
| + for(k=0; k<pEList->nExpr; k++){
|
| + pE = pEList->a[k].pExpr;
|
| + if( pE->op==TK_ASTERISK ) break;
|
| + assert( pE->op!=TK_DOT || pE->pRight!=0 );
|
| + assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
|
| + if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break;
|
| + }
|
| + if( k<pEList->nExpr ){
|
| + /*
|
| + ** If we get here it means the result set contains one or more "*"
|
| + ** operators that need to be expanded. Loop through each expression
|
| + ** in the result set and expand them one by one.
|
| + */
|
| + struct ExprList_item *a = pEList->a;
|
| + ExprList *pNew = 0;
|
| + int flags = pParse->db->flags;
|
| + int longNames = (flags & SQLITE_FullColNames)!=0
|
| + && (flags & SQLITE_ShortColNames)==0;
|
| +
|
| + for(k=0; k<pEList->nExpr; k++){
|
| + pE = a[k].pExpr;
|
| + pRight = pE->pRight;
|
| + assert( pE->op!=TK_DOT || pRight!=0 );
|
| + if( pE->op!=TK_ASTERISK
|
| + && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK)
|
| + ){
|
| + /* This particular expression does not need to be expanded.
|
| + */
|
| + pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
|
| + if( pNew ){
|
| + pNew->a[pNew->nExpr-1].zName = a[k].zName;
|
| + pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan;
|
| + a[k].zName = 0;
|
| + a[k].zSpan = 0;
|
| + }
|
| + a[k].pExpr = 0;
|
| + }else{
|
| + /* This expression is a "*" or a "TABLE.*" and needs to be
|
| + ** expanded. */
|
| + int tableSeen = 0; /* Set to 1 when TABLE matches */
|
| + char *zTName = 0; /* text of name of TABLE */
|
| + if( pE->op==TK_DOT ){
|
| + assert( pE->pLeft!=0 );
|
| + assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
|
| + zTName = pE->pLeft->u.zToken;
|
| + }
|
| + for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
| + Table *pTab = pFrom->pTab;
|
| + Select *pSub = pFrom->pSelect;
|
| + char *zTabName = pFrom->zAlias;
|
| + const char *zSchemaName = 0;
|
| + int iDb;
|
| + if( zTabName==0 ){
|
| + zTabName = pTab->zName;
|
| + }
|
| + if( db->mallocFailed ) break;
|
| + if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
|
| + pSub = 0;
|
| + if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
|
| + continue;
|
| + }
|
| + iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| + zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
|
| + }
|
| + for(j=0; j<pTab->nCol; j++){
|
| + char *zName = pTab->aCol[j].zName;
|
| + char *zColname; /* The computed column name */
|
| + char *zToFree; /* Malloced string that needs to be freed */
|
| + Token sColname; /* Computed column name as a token */
|
| +
|
| + assert( zName );
|
| + if( zTName && pSub
|
| + && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
|
| + ){
|
| + continue;
|
| + }
|
| +
|
| + /* If a column is marked as 'hidden', omit it from the expanded
|
| + ** result-set list unless the SELECT has the SF_IncludeHidden
|
| + ** bit set.
|
| + */
|
| + if( (p->selFlags & SF_IncludeHidden)==0
|
| + && IsHiddenColumn(&pTab->aCol[j])
|
| + ){
|
| + continue;
|
| + }
|
| + tableSeen = 1;
|
| +
|
| + if( i>0 && zTName==0 ){
|
| + if( (pFrom->fg.jointype & JT_NATURAL)!=0
|
| + && tableAndColumnIndex(pTabList, i, zName, 0, 0)
|
| + ){
|
| + /* In a NATURAL join, omit the join columns from the
|
| + ** table to the right of the join */
|
| + continue;
|
| + }
|
| + if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){
|
| + /* In a join with a USING clause, omit columns in the
|
| + ** using clause from the table on the right. */
|
| + continue;
|
| + }
|
| + }
|
| + pRight = sqlite3Expr(db, TK_ID, zName);
|
| + zColname = zName;
|
| + zToFree = 0;
|
| + if( longNames || pTabList->nSrc>1 ){
|
| + Expr *pLeft;
|
| + pLeft = sqlite3Expr(db, TK_ID, zTabName);
|
| + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
|
| + if( zSchemaName ){
|
| + pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
|
| + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
|
| + }
|
| + if( longNames ){
|
| + zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
|
| + zToFree = zColname;
|
| + }
|
| + }else{
|
| + pExpr = pRight;
|
| + }
|
| + pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
|
| + sColname.z = zColname;
|
| + sColname.n = sqlite3Strlen30(zColname);
|
| + sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
|
| + if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
|
| + struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
|
| + if( pSub ){
|
| + pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
|
| + testcase( pX->zSpan==0 );
|
| + }else{
|
| + pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
|
| + zSchemaName, zTabName, zColname);
|
| + testcase( pX->zSpan==0 );
|
| + }
|
| + pX->bSpanIsTab = 1;
|
| + }
|
| + sqlite3DbFree(db, zToFree);
|
| + }
|
| + }
|
| + if( !tableSeen ){
|
| + if( zTName ){
|
| + sqlite3ErrorMsg(pParse, "no such table: %s", zTName);
|
| + }else{
|
| + sqlite3ErrorMsg(pParse, "no tables specified");
|
| + }
|
| + }
|
| + }
|
| + }
|
| + sqlite3ExprListDelete(db, pEList);
|
| + p->pEList = pNew;
|
| + }
|
| +#if SQLITE_MAX_COLUMN
|
| + if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
| + sqlite3ErrorMsg(pParse, "too many columns in result set");
|
| + return WRC_Abort;
|
| + }
|
| +#endif
|
| + return WRC_Continue;
|
| +}
|
| +
|
| +/*
|
| +** No-op routine for the parse-tree walker.
|
| +**
|
| +** When this routine is the Walker.xExprCallback then expression trees
|
| +** are walked without any actions being taken at each node. Presumably,
|
| +** when this routine is used for Walker.xExprCallback then
|
| +** Walker.xSelectCallback is set to do something useful for every
|
| +** subquery in the parser tree.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
|
| + UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
| + return WRC_Continue;
|
| +}
|
| +
|
| +/*
|
| +** This routine "expands" a SELECT statement and all of its subqueries.
|
| +** For additional information on what it means to "expand" a SELECT
|
| +** statement, see the comment on the selectExpand worker callback above.
|
| +**
|
| +** Expanding a SELECT statement is the first step in processing a
|
| +** SELECT statement. The SELECT statement must be expanded before
|
| +** name resolution is performed.
|
| +**
|
| +** If anything goes wrong, an error message is written into pParse.
|
| +** The calling function can detect the problem by looking at pParse->nErr
|
| +** and/or pParse->db->mallocFailed.
|
| +*/
|
| +static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
|
| + Walker w;
|
| + memset(&w, 0, sizeof(w));
|
| + w.xExprCallback = sqlite3ExprWalkNoop;
|
| + w.pParse = pParse;
|
| + if( pParse->hasCompound ){
|
| + w.xSelectCallback = convertCompoundSelectToSubquery;
|
| + sqlite3WalkSelect(&w, pSelect);
|
| + }
|
| + w.xSelectCallback = selectExpander;
|
| + if( (pSelect->selFlags & SF_MultiValue)==0 ){
|
| + w.xSelectCallback2 = selectPopWith;
|
| + }
|
| + sqlite3WalkSelect(&w, pSelect);
|
| +}
|
| +
|
| +
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| +/*
|
| +** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo()
|
| +** interface.
|
| +**
|
| +** For each FROM-clause subquery, add Column.zType and Column.zColl
|
| +** information to the Table structure that represents the result set
|
| +** of that subquery.
|
| +**
|
| +** The Table structure that represents the result set was constructed
|
| +** by selectExpander() but the type and collation information was omitted
|
| +** at that point because identifiers had not yet been resolved. This
|
| +** routine is called after identifier resolution.
|
| +*/
|
| +static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
| + Parse *pParse;
|
| + int i;
|
| + SrcList *pTabList;
|
| + struct SrcList_item *pFrom;
|
| +
|
| + assert( p->selFlags & SF_Resolved );
|
| + assert( (p->selFlags & SF_HasTypeInfo)==0 );
|
| + p->selFlags |= SF_HasTypeInfo;
|
| + pParse = pWalker->pParse;
|
| + pTabList = p->pSrc;
|
| + for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
| + Table *pTab = pFrom->pTab;
|
| + assert( pTab!=0 );
|
| + if( (pTab->tabFlags & TF_Ephemeral)!=0 ){
|
| + /* A sub-query in the FROM clause of a SELECT */
|
| + Select *pSel = pFrom->pSelect;
|
| + if( pSel ){
|
| + while( pSel->pPrior ) pSel = pSel->pPrior;
|
| + selectAddColumnTypeAndCollation(pParse, pTab, pSel);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** This routine adds datatype and collating sequence information to
|
| +** the Table structures of all FROM-clause subqueries in a
|
| +** SELECT statement.
|
| +**
|
| +** Use this routine after name resolution.
|
| +*/
|
| +static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| + Walker w;
|
| + memset(&w, 0, sizeof(w));
|
| + w.xSelectCallback2 = selectAddSubqueryTypeInfo;
|
| + w.xExprCallback = sqlite3ExprWalkNoop;
|
| + w.pParse = pParse;
|
| + sqlite3WalkSelect(&w, pSelect);
|
| +#endif
|
| +}
|
| +
|
| +
|
| +/*
|
| +** This routine sets up a SELECT statement for processing. The
|
| +** following is accomplished:
|
| +**
|
| +** * VDBE Cursor numbers are assigned to all FROM-clause terms.
|
| +** * Ephemeral Table objects are created for all FROM-clause subqueries.
|
| +** * ON and USING clauses are shifted into WHERE statements
|
| +** * Wildcards "*" and "TABLE.*" in result sets are expanded.
|
| +** * Identifiers in expression are matched to tables.
|
| +**
|
| +** This routine acts recursively on all subqueries within the SELECT.
|
| +*/
|
| +SQLITE_PRIVATE void sqlite3SelectPrep(
|
| + Parse *pParse, /* The parser context */
|
| + Select *p, /* The SELECT statement being coded. */
|
| + NameContext *pOuterNC /* Name context for container */
|
| +){
|
| + sqlite3 *db;
|
| + if( NEVER(p==0) ) return;
|
| + db = pParse->db;
|
| + if( db->mallocFailed ) return;
|
| + if( p->selFlags & SF_HasTypeInfo ) return;
|
| + sqlite3SelectExpand(pParse, p);
|
| + if( pParse->nErr || db->mallocFailed ) return;
|
| + sqlite3ResolveSelectNames(pParse, p, pOuterNC);
|
| + if( pParse->nErr || db->mallocFailed ) return;
|
| + sqlite3SelectAddTypeInfo(pParse, p);
|
| +}
|
| +
|
| +/*
|
| +** Reset the aggregate accumulator.
|
| +**
|
| +** The aggregate accumulator is a set of memory cells that hold
|
| +** intermediate results while calculating an aggregate. This
|
| +** routine generates code that stores NULLs in all of those memory
|
| +** cells.
|
| +*/
|
| +static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
| + Vdbe *v = pParse->pVdbe;
|
| + int i;
|
| + struct AggInfo_func *pFunc;
|
| + int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
|
| + if( nReg==0 ) return;
|
| +#ifdef SQLITE_DEBUG
|
| + /* Verify that all AggInfo registers are within the range specified by
|
| + ** AggInfo.mnReg..AggInfo.mxReg */
|
| + assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
|
| + for(i=0; i<pAggInfo->nColumn; i++){
|
| + assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
|
| + && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
|
| + }
|
| + for(i=0; i<pAggInfo->nFunc; i++){
|
| + assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
|
| + && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
|
| + }
|
| +#endif
|
| + sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
|
| + for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
|
| + if( pFunc->iDistinct>=0 ){
|
| + Expr *pE = pFunc->pExpr;
|
| + assert( !ExprHasProperty(pE, EP_xIsSelect) );
|
| + if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
|
| + sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
|
| + "argument");
|
| + pFunc->iDistinct = -1;
|
| + }else{
|
| + KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
|
| + sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
|
| + (char*)pKeyInfo, P4_KEYINFO);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Invoke the OP_AggFinalize opcode for every aggregate function
|
| +** in the AggInfo structure.
|
| +*/
|
| +static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
| + Vdbe *v = pParse->pVdbe;
|
| + int i;
|
| + struct AggInfo_func *pF;
|
| + for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
| + ExprList *pList = pF->pExpr->x.pList;
|
| + assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
| + 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;
|
| + int regHit = 0;
|
| + int addrHitTest = 0;
|
| + struct AggInfo_func *pF;
|
| + struct AggInfo_col *pC;
|
| +
|
| + pAggInfo->directMode = 1;
|
| + for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
| + int nArg;
|
| + int addrNext = 0;
|
| + int regAgg;
|
| + ExprList *pList = pF->pExpr->x.pList;
|
| + assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
| + if( pList ){
|
| + nArg = pList->nExpr;
|
| + regAgg = sqlite3GetTempRange(pParse, nArg);
|
| + sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP);
|
| + }else{
|
| + nArg = 0;
|
| + regAgg = 0;
|
| + }
|
| + if( pF->iDistinct>=0 ){
|
| + addrNext = sqlite3VdbeMakeLabel(v);
|
| + testcase( nArg==0 ); /* Error condition */
|
| + testcase( nArg>1 ); /* Also an error */
|
| + codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
|
| + }
|
| + if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
| + CollSeq *pColl = 0;
|
| + struct ExprList_item *pItem;
|
| + int j;
|
| + assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
|
| + for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
|
| + pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
| + }
|
| + if( !pColl ){
|
| + pColl = pParse->db->pDfltColl;
|
| + }
|
| + if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
|
| + sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
|
| + }
|
| + sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem,
|
| + (void*)pF->pFunc, P4_FUNCDEF);
|
| + sqlite3VdbeChangeP5(v, (u8)nArg);
|
| + sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
|
| + sqlite3ReleaseTempRange(pParse, regAgg, nArg);
|
| + if( addrNext ){
|
| + sqlite3VdbeResolveLabel(v, addrNext);
|
| + sqlite3ExprCacheClear(pParse);
|
| + }
|
| + }
|
| +
|
| + /* Before populating the accumulator registers, clear the column cache.
|
| + ** Otherwise, if any of the required column values are already present
|
| + ** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value
|
| + ** to pC->iMem. But by the time the value is used, the original register
|
| + ** may have been used, invalidating the underlying buffer holding the
|
| + ** text or blob value. See ticket [883034dcb5].
|
| + **
|
| + ** Another solution would be to change the OP_SCopy used to copy cached
|
| + ** values to an OP_Copy.
|
| + */
|
| + if( regHit ){
|
| + addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
|
| + }
|
| + sqlite3ExprCacheClear(pParse);
|
| + for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
|
| + sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
|
| + }
|
| + pAggInfo->directMode = 0;
|
| + sqlite3ExprCacheClear(pParse);
|
| + if( addrHitTest ){
|
| + sqlite3VdbeJumpHere(v, addrHitTest);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Add a single OP_Explain instruction to the VDBE to explain a simple
|
| +** count(*) query ("SELECT count(*) FROM pTab").
|
| +*/
|
| +#ifndef SQLITE_OMIT_EXPLAIN
|
| +static void explainSimpleCount(
|
| + Parse *pParse, /* Parse context */
|
| + Table *pTab, /* Table being queried */
|
| + Index *pIdx /* Index used to optimize scan, or NULL */
|
| +){
|
| + if( pParse->explain==2 ){
|
| + int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx)));
|
| + char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s",
|
| + pTab->zName,
|
| + bCover ? " USING COVERING INDEX " : "",
|
| + bCover ? pIdx->zName : ""
|
| + );
|
| + sqlite3VdbeAddOp4(
|
| + pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC
|
| + );
|
| + }
|
| +}
|
| +#else
|
| +# define explainSimpleCount(a,b,c)
|
| +#endif
|
| +
|
| +/*
|
| +** Generate code for the SELECT statement given in the p argument.
|
| +**
|
| +** The results are returned according to the SelectDest structure.
|
| +** See comments in sqliteInt.h for further information.
|
| +**
|
| +** This routine returns the number of errors. If any errors are
|
| +** encountered, then an appropriate error message is left in
|
| +** pParse->zErrMsg.
|
| +**
|
| +** This routine does NOT free the Select structure passed in. The
|
| +** calling function needs to do that.
|
| +*/
|
| +SQLITE_PRIVATE int sqlite3Select(
|
| + Parse *pParse, /* The parser context */
|
| + Select *p, /* The SELECT statement being coded. */
|
| + SelectDest *pDest /* What to do with the query results */
|
| +){
|
| + int i, j; /* Loop counters */
|
| + WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */
|
| + Vdbe *v; /* The virtual machine under construction */
|
| + int isAgg; /* True for select lists like "count(*)" */
|
| + ExprList *pEList = 0; /* List of columns to extract. */
|
| + SrcList *pTabList; /* List of tables to select from */
|
| + Expr *pWhere; /* The WHERE clause. May be NULL */
|
| + ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
| + Expr *pHaving; /* The HAVING clause. May be NULL */
|
| + int rc = 1; /* Value to return from this function */
|
| + DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
|
| + SortCtx sSort; /* Info on how to code the ORDER BY clause */
|
| + AggInfo sAggInfo; /* Information used by aggregate queries */
|
| + int iEnd; /* Address of the end of the query */
|
| + sqlite3 *db; /* The database connection */
|
| +
|
| +#ifndef SQLITE_OMIT_EXPLAIN
|
| + int iRestoreSelectId = pParse->iSelectId;
|
| + pParse->iSelectId = pParse->iNextSelectId++;
|
| +#endif
|
| +
|
| + db = pParse->db;
|
| + if( p==0 || db->mallocFailed || pParse->nErr ){
|
| + return 1;
|
| + }
|
| + if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
| + memset(&sAggInfo, 0, sizeof(sAggInfo));
|
| +#if SELECTTRACE_ENABLED
|
| + pParse->nSelectIndent++;
|
| + SELECTTRACE(1,pParse,p, ("begin processing:\n"));
|
| + if( sqlite3SelectTrace & 0x100 ){
|
| + sqlite3TreeViewSelect(0, p, 0);
|
| + }
|
| +#endif
|
| +
|
| + assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
|
| + assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
|
| + assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
|
| + assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
|
| + if( IgnorableOrderby(pDest) ){
|
| + assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
|
| + pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
|
| + pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
|
| + pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
|
| + /* If ORDER BY makes no difference in the output then neither does
|
| + ** DISTINCT so it can be removed too. */
|
| + sqlite3ExprListDelete(db, p->pOrderBy);
|
| + p->pOrderBy = 0;
|
| + p->selFlags &= ~SF_Distinct;
|
| + }
|
| + sqlite3SelectPrep(pParse, p, 0);
|
| + memset(&sSort, 0, sizeof(sSort));
|
| + sSort.pOrderBy = p->pOrderBy;
|
| + pTabList = p->pSrc;
|
| + if( pParse->nErr || db->mallocFailed ){
|
| + goto select_end;
|
| + }
|
| + assert( p->pEList!=0 );
|
| + isAgg = (p->selFlags & SF_Aggregate)!=0;
|
| +#if SELECTTRACE_ENABLED
|
| + if( sqlite3SelectTrace & 0x100 ){
|
| + SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
|
| + sqlite3TreeViewSelect(0, p, 0);
|
| + }
|
| +#endif
|
| +
|
| +
|
| + /* If writing to memory or generating a set
|
| + ** only a single column may be output.
|
| + */
|
| +#ifndef SQLITE_OMIT_SUBQUERY
|
| + if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
|
| + goto select_end;
|
| + }
|
| +#endif
|
| +
|
| + /* Try to flatten subqueries in the FROM clause up into the main query
|
| + */
|
| +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
| + for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
|
| + struct SrcList_item *pItem = &pTabList->a[i];
|
| + Select *pSub = pItem->pSelect;
|
| + int isAggSub;
|
| + Table *pTab = pItem->pTab;
|
| + if( pSub==0 ) continue;
|
| +
|
| + /* Catch mismatch in the declared columns of a view and the number of
|
| + ** columns in the SELECT on the RHS */
|
| + if( pTab->nCol!=pSub->pEList->nExpr ){
|
| + sqlite3ErrorMsg(pParse, "expected %d columns for '%s' but got %d",
|
| + pTab->nCol, pTab->zName, pSub->pEList->nExpr);
|
| + goto select_end;
|
| + }
|
| +
|
| + isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
|
| + if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
|
| + /* This subquery can be absorbed into its parent. */
|
| + if( isAggSub ){
|
| + isAgg = 1;
|
| + p->selFlags |= SF_Aggregate;
|
| + }
|
| + i = -1;
|
| + }
|
| + pTabList = p->pSrc;
|
| + if( db->mallocFailed ) goto select_end;
|
| + if( !IgnorableOrderby(pDest) ){
|
| + sSort.pOrderBy = p->pOrderBy;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + /* Get a pointer the VDBE under construction, allocating a new VDBE if one
|
| + ** does not already exist */
|
| + v = sqlite3GetVdbe(pParse);
|
| + if( v==0 ) goto select_end;
|
| +
|
| +#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
| + /* Handle compound SELECT statements using the separate multiSelect()
|
| + ** procedure.
|
| + */
|
| + if( p->pPrior ){
|
| + rc = multiSelect(pParse, p, pDest);
|
| + explainSetInteger(pParse->iSelectId, iRestoreSelectId);
|
| +#if SELECTTRACE_ENABLED
|
| + SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
|
| + pParse->nSelectIndent--;
|
| +#endif
|
| + return rc;
|
| + }
|
| +#endif
|
| +
|
| + /* Generate code for all sub-queries in the FROM clause
|
| + */
|
| +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
| + for(i=0; i<pTabList->nSrc; i++){
|
| + struct SrcList_item *pItem = &pTabList->a[i];
|
| + SelectDest dest;
|
| + Select *pSub = pItem->pSelect;
|
| + if( pSub==0 ) continue;
|
| +
|
| + /* Sometimes the code for a subquery will be generated more than
|
| + ** once, if the subquery is part of the WHERE clause in a LEFT JOIN,
|
| + ** for example. In that case, do not regenerate the code to manifest
|
| + ** a view or the co-routine to implement a view. The first instance
|
| + ** is sufficient, though the subroutine to manifest the view does need
|
| + ** to be invoked again. */
|
| + if( pItem->addrFillSub ){
|
| + if( pItem->fg.viaCoroutine==0 ){
|
| + sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
|
| + }
|
| + continue;
|
| + }
|
| +
|
| + /* Increment Parse.nHeight by the height of the largest expression
|
| + ** tree referred to by this, the parent select. The child select
|
| + ** may contain expression trees of at most
|
| + ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
|
| + ** more conservative than necessary, but much easier than enforcing
|
| + ** an exact limit.
|
| + */
|
| + pParse->nHeight += sqlite3SelectExprHeight(p);
|
| +
|
| + /* Make copies of constant WHERE-clause terms in the outer query down
|
| + ** inside the subquery. This can help the subquery to run more efficiently.
|
| + */
|
| + if( (pItem->fg.jointype & JT_OUTER)==0
|
| + && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
|
| + ){
|
| +#if SELECTTRACE_ENABLED
|
| + if( sqlite3SelectTrace & 0x100 ){
|
| + SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n"));
|
| + sqlite3TreeViewSelect(0, p, 0);
|
| + }
|
| +#endif
|
| + }
|
| +
|
| + /* Generate code to implement the subquery
|
| + */
|
| + if( pTabList->nSrc==1
|
| + && (p->selFlags & SF_All)==0
|
| + && OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
| + ){
|
| + /* Implement a co-routine that will return a single row of the result
|
| + ** set on each invocation.
|
| + */
|
| + int addrTop = sqlite3VdbeCurrentAddr(v)+1;
|
| + pItem->regReturn = ++pParse->nMem;
|
| + sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
|
| + VdbeComment((v, "%s", pItem->pTab->zName));
|
| + pItem->addrFillSub = addrTop;
|
| + sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
| + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
| + sqlite3Select(pParse, pSub, &dest);
|
| + pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
| + pItem->fg.viaCoroutine = 1;
|
| + pItem->regResult = dest.iSdst;
|
| + sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
| + sqlite3VdbeJumpHere(v, addrTop-1);
|
| + sqlite3ClearTempRegCache(pParse);
|
| + }else{
|
| + /* Generate a subroutine that will fill an ephemeral table with
|
| + ** the content of this subquery. pItem->addrFillSub will point
|
| + ** to the address of the generated subroutine. pItem->regReturn
|
| + ** is a register allocated to hold the subroutine return address
|
| + */
|
| + int topAddr;
|
| + int onceAddr = 0;
|
| + int retAddr;
|
| + assert( pItem->addrFillSub==0 );
|
| + pItem->regReturn = ++pParse->nMem;
|
| + topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
| + pItem->addrFillSub = topAddr+1;
|
| + if( pItem->fg.isCorrelated==0 ){
|
| + /* If the subquery is not correlated and if we are not inside of
|
| + ** a trigger, then we only need to compute the value of the subquery
|
| + ** once. */
|
| + onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
| + VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
| + }else{
|
| + VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
| + }
|
| + sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
| + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
| + sqlite3Select(pParse, pSub, &dest);
|
| + pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
| + if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
| + retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
| + VdbeComment((v, "end %s", pItem->pTab->zName));
|
| + sqlite3VdbeChangeP1(v, topAddr, retAddr);
|
| + sqlite3ClearTempRegCache(pParse);
|
| + }
|
| + if( db->mallocFailed ) goto select_end;
|
| + pParse->nHeight -= sqlite3SelectExprHeight(p);
|
| + }
|
| +#endif
|
| +
|
| + /* Various elements of the SELECT copied into local variables for
|
| + ** convenience */
|
| + pEList = p->pEList;
|
| + pWhere = p->pWhere;
|
| + pGroupBy = p->pGroupBy;
|
| + pHaving = p->pHaving;
|
| + sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
|
| +
|
| +#if SELECTTRACE_ENABLED
|
| + if( sqlite3SelectTrace & 0x400 ){
|
| + SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
|
| + sqlite3TreeViewSelect(0, p, 0);
|
| + }
|
| +#endif
|
| +
|
| + /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
| + ** if the select-list is the same as the ORDER BY list, then this query
|
| + ** can be rewritten as a GROUP BY. In other words, this:
|
| + **
|
| + ** SELECT DISTINCT xyz FROM ... ORDER BY xyz
|
| + **
|
| + ** is transformed to:
|
| + **
|
| + ** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz
|
| + **
|
| + ** The second form is preferred as a single index (or temp-table) may be
|
| + ** used for both the ORDER BY and DISTINCT processing. As originally
|
| + ** written the query must use a temp-table for at least one of the ORDER
|
| + ** BY and DISTINCT, and an index or separate temp-table for the other.
|
| + */
|
| + if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
| + && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
|
| + ){
|
| + p->selFlags &= ~SF_Distinct;
|
| + pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
|
| + /* Notice that even thought SF_Distinct has been cleared from p->selFlags,
|
| + ** the sDistinct.isTnct is still set. Hence, isTnct represents the
|
| + ** original setting of the SF_Distinct flag, not the current setting */
|
| + assert( sDistinct.isTnct );
|
| + }
|
| +
|
| + /* If there is an ORDER BY clause, then create an ephemeral index to
|
| + ** do the sorting. But this sorting ephemeral index might end up
|
| + ** being unused if the data can be extracted in pre-sorted order.
|
| + ** If that is the case, then the OP_OpenEphemeral instruction will be
|
| + ** changed to an OP_Noop once we figure out that the sorting index is
|
| + ** not needed. The sSort.addrSortIndex variable is used to facilitate
|
| + ** that change.
|
| + */
|
| + if( sSort.pOrderBy ){
|
| + KeyInfo *pKeyInfo;
|
| + pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
|
| + sSort.iECursor = pParse->nTab++;
|
| + sSort.addrSortIndex =
|
| + sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
| + sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0,
|
| + (char*)pKeyInfo, P4_KEYINFO
|
| + );
|
| + }else{
|
| + sSort.addrSortIndex = -1;
|
| + }
|
| +
|
| + /* If the output is destined for a temporary table, open that table.
|
| + */
|
| + if( pDest->eDest==SRT_EphemTab ){
|
| + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
|
| + }
|
| +
|
| + /* Set the limiter.
|
| + */
|
| + iEnd = sqlite3VdbeMakeLabel(v);
|
| + p->nSelectRow = LARGEST_INT64;
|
| + computeLimitRegisters(pParse, p, iEnd);
|
| + if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
|
| + sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
|
| + sSort.sortFlags |= SORTFLAG_UseSorter;
|
| + }
|
| +
|
| + /* Open an ephemeral index to use for the distinct set.
|
| + */
|
| + if( p->selFlags & SF_Distinct ){
|
| + sDistinct.tabTnct = pParse->nTab++;
|
| + sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
| + sDistinct.tabTnct, 0, 0,
|
| + (char*)keyInfoFromExprList(pParse, p->pEList,0,0),
|
| + P4_KEYINFO);
|
| + sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
| + sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
|
| + }else{
|
| + sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
|
| + }
|
| +
|
| + if( !isAgg && pGroupBy==0 ){
|
| + /* No aggregate functions and no GROUP BY clause */
|
| + u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
|
| +
|
| + /* Begin the database scan. */
|
| + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
|
| + p->pEList, wctrlFlags, 0);
|
| + if( pWInfo==0 ) goto select_end;
|
| + if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
|
| + p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
|
| + }
|
| + if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
|
| + sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
|
| + }
|
| + if( sSort.pOrderBy ){
|
| + sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
|
| + if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
|
| + sSort.pOrderBy = 0;
|
| + }
|
| + }
|
| +
|
| + /* If sorting index that was created by a prior OP_OpenEphemeral
|
| + ** instruction ended up not being needed, then change the OP_OpenEphemeral
|
| + ** into an OP_Noop.
|
| + */
|
| + if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){
|
| + sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
|
| + }
|
| +
|
| + /* Use the standard inner loop. */
|
| + selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
|
| + sqlite3WhereContinueLabel(pWInfo),
|
| + sqlite3WhereBreakLabel(pWInfo));
|
| +
|
| + /* End the database scan loop.
|
| + */
|
| + sqlite3WhereEnd(pWInfo);
|
| + }else{
|
| + /* This case when there exist aggregate functions or a GROUP BY clause
|
| + ** or both */
|
| + NameContext sNC; /* Name context for processing aggregate information */
|
| + int iAMem; /* First Mem address for storing current GROUP BY */
|
| + int iBMem; /* First Mem address for previous GROUP BY */
|
| + int iUseFlag; /* Mem address holding flag indicating that at least
|
| + ** one row of the input to the aggregator has been
|
| + ** processed */
|
| + int iAbortFlag; /* Mem address which causes query abort if positive */
|
| + int groupBySort; /* Rows come from source in GROUP BY order */
|
| + int addrEnd; /* End of processing for this SELECT */
|
| + int sortPTab = 0; /* Pseudotable used to decode sorting results */
|
| + int sortOut = 0; /* Output register from the sorter */
|
| + int orderByGrp = 0; /* True if the GROUP BY and ORDER BY are the same */
|
| +
|
| + /* Remove any and all aliases between the result set and the
|
| + ** GROUP BY clause.
|
| + */
|
| + if( pGroupBy ){
|
| + int k; /* Loop counter */
|
| + struct ExprList_item *pItem; /* For looping over expression in a list */
|
| +
|
| + for(k=p->pEList->nExpr, pItem=p->pEList->a; k>0; k--, pItem++){
|
| + pItem->u.x.iAlias = 0;
|
| + }
|
| + for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
|
| + pItem->u.x.iAlias = 0;
|
| + }
|
| + if( p->nSelectRow>100 ) p->nSelectRow = 100;
|
| + }else{
|
| + p->nSelectRow = 1;
|
| + }
|
| +
|
| + /* If there is both a GROUP BY and an ORDER BY clause and they are
|
| + ** identical, then it may be possible to disable the ORDER BY clause
|
| + ** on the grounds that the GROUP BY will cause elements to come out
|
| + ** in the correct order. It also may not - the GROUP BY might use a
|
| + ** database index that causes rows to be grouped together as required
|
| + ** but not actually sorted. Either way, record the fact that the
|
| + ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
|
| + ** variable. */
|
| + if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
|
| + orderByGrp = 1;
|
| + }
|
| +
|
| + /* Create a label to jump to when we want to abort the query */
|
| + addrEnd = sqlite3VdbeMakeLabel(v);
|
| +
|
| + /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in
|
| + ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
|
| + ** SELECT statement.
|
| + */
|
| + memset(&sNC, 0, sizeof(sNC));
|
| + sNC.pParse = pParse;
|
| + sNC.pSrcList = pTabList;
|
| + sNC.pAggInfo = &sAggInfo;
|
| + sAggInfo.mnReg = pParse->nMem+1;
|
| + sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
| + sAggInfo.pGroupBy = pGroupBy;
|
| + sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
| + sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
| + if( pHaving ){
|
| + sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
| + }
|
| + sAggInfo.nAccumulator = sAggInfo.nColumn;
|
| + for(i=0; i<sAggInfo.nFunc; i++){
|
| + assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
|
| + sNC.ncFlags |= NC_InAggFunc;
|
| + sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
|
| + sNC.ncFlags &= ~NC_InAggFunc;
|
| + }
|
| + sAggInfo.mxReg = pParse->nMem;
|
| + if( db->mallocFailed ) goto select_end;
|
| +
|
| + /* Processing for aggregates with GROUP BY is very different and
|
| + ** much more complex than aggregates without a GROUP BY.
|
| + */
|
| + if( pGroupBy ){
|
| + KeyInfo *pKeyInfo; /* Keying information for the group by clause */
|
| + int addr1; /* A-vs-B comparision jump */
|
| + int addrOutputRow; /* Start of subroutine that outputs a result row */
|
| + int regOutputRow; /* Return address register for output subroutine */
|
| + int addrSetAbort; /* Set the abort flag and return */
|
| + int addrTopOfLoop; /* Top of the input loop */
|
| + int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */
|
| + int addrReset; /* Subroutine for resetting the accumulator */
|
| + int regReset; /* Return address register for reset subroutine */
|
| +
|
| + /* If there is a GROUP BY clause we might need a sorting index to
|
| + ** implement it. Allocate that sorting index now. If it turns out
|
| + ** that we do not need it after all, the OP_SorterOpen instruction
|
| + ** will be converted into a Noop.
|
| + */
|
| + sAggInfo.sortingIdx = pParse->nTab++;
|
| + pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn);
|
| + addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
| + sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
| + 0, (char*)pKeyInfo, P4_KEYINFO);
|
| +
|
| + /* Initialize memory locations used by GROUP BY aggregate processing
|
| + */
|
| + iUseFlag = ++pParse->nMem;
|
| + iAbortFlag = ++pParse->nMem;
|
| + regOutputRow = ++pParse->nMem;
|
| + addrOutputRow = sqlite3VdbeMakeLabel(v);
|
| + regReset = ++pParse->nMem;
|
| + addrReset = sqlite3VdbeMakeLabel(v);
|
| + iAMem = pParse->nMem + 1;
|
| + pParse->nMem += pGroupBy->nExpr;
|
| + iBMem = pParse->nMem + 1;
|
| + pParse->nMem += pGroupBy->nExpr;
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
|
| + VdbeComment((v, "clear abort flag"));
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
| + VdbeComment((v, "indicate accumulator empty"));
|
| + sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
|
| +
|
| + /* Begin a loop that will extract all source rows in GROUP BY order.
|
| + ** This might involve two separate loops with an OP_Sort in between, or
|
| + ** it might be a single loop that uses an index to extract information
|
| + ** in the right order to begin with.
|
| + */
|
| + sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
| + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
|
| + WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0
|
| + );
|
| + if( pWInfo==0 ) goto select_end;
|
| + if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
|
| + /* The optimizer is able to deliver rows in group by order so
|
| + ** we do not have to sort. The OP_OpenEphemeral table will be
|
| + ** cancelled later because we still need to use the pKeyInfo
|
| + */
|
| + groupBySort = 0;
|
| + }else{
|
| + /* Rows are coming out in undetermined order. We have to push
|
| + ** each row into a sorting index, terminate the first loop,
|
| + ** then loop over the sorting index in order to get the output
|
| + ** in sorted order
|
| + */
|
| + int regBase;
|
| + int regRecord;
|
| + int nCol;
|
| + int nGroupBy;
|
| +
|
| + explainTempTable(pParse,
|
| + (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
|
| + "DISTINCT" : "GROUP BY");
|
| +
|
| + groupBySort = 1;
|
| + nGroupBy = pGroupBy->nExpr;
|
| + nCol = nGroupBy;
|
| + j = nGroupBy;
|
| + for(i=0; i<sAggInfo.nColumn; i++){
|
| + if( sAggInfo.aCol[i].iSorterColumn>=j ){
|
| + nCol++;
|
| + j++;
|
| + }
|
| + }
|
| + regBase = sqlite3GetTempRange(pParse, nCol);
|
| + sqlite3ExprCacheClear(pParse);
|
| + sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
|
| + j = nGroupBy;
|
| + for(i=0; i<sAggInfo.nColumn; i++){
|
| + struct AggInfo_col *pCol = &sAggInfo.aCol[i];
|
| + if( pCol->iSorterColumn>=j ){
|
| + int r1 = j + regBase;
|
| + sqlite3ExprCodeGetColumnToReg(pParse,
|
| + pCol->pTab, pCol->iColumn, pCol->iTable, r1);
|
| + j++;
|
| + }
|
| + }
|
| + regRecord = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
|
| + sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
|
| + sqlite3ReleaseTempReg(pParse, regRecord);
|
| + sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
| + sqlite3WhereEnd(pWInfo);
|
| + sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
|
| + sortOut = sqlite3GetTempReg(pParse);
|
| + sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
|
| + sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
|
| + VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
|
| + sAggInfo.useSortingIdx = 1;
|
| + sqlite3ExprCacheClear(pParse);
|
| +
|
| + }
|
| +
|
| + /* If the index or temporary table used by the GROUP BY sort
|
| + ** will naturally deliver rows in the order required by the ORDER BY
|
| + ** clause, cancel the ephemeral table open coded earlier.
|
| + **
|
| + ** This is an optimization - the correct answer should result regardless.
|
| + ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to
|
| + ** disable this optimization for testing purposes. */
|
| + if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder)
|
| + && (groupBySort || sqlite3WhereIsSorted(pWInfo))
|
| + ){
|
| + sSort.pOrderBy = 0;
|
| + sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
|
| + }
|
| +
|
| + /* Evaluate the current GROUP BY terms and store in b0, b1, b2...
|
| + ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth)
|
| + ** Then compare the current GROUP BY terms against the GROUP BY terms
|
| + ** from the previous row currently stored in a0, a1, a2...
|
| + */
|
| + addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3ExprCacheClear(pParse);
|
| + if( groupBySort ){
|
| + sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
|
| + sortOut, sortPTab);
|
| + }
|
| + for(j=0; j<pGroupBy->nExpr; j++){
|
| + if( groupBySort ){
|
| + sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
|
| + }else{
|
| + sAggInfo.directMode = 1;
|
| + sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
|
| + }
|
| + }
|
| + sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
|
| + (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
|
| + addr1 = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp3(v, OP_Jump, addr1+1, 0, addr1+1); VdbeCoverage(v);
|
| +
|
| + /* Generate code that runs whenever the GROUP BY changes.
|
| + ** Changes in the GROUP BY are detected by the previous code
|
| + ** block. If there were no changes, this block is skipped.
|
| + **
|
| + ** This code copies current group by terms in b0,b1,b2,...
|
| + ** over to a0,a1,a2. It then calls the output subroutine
|
| + ** and resets the aggregate accumulator registers in preparation
|
| + ** for the next GROUP BY batch.
|
| + */
|
| + sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr);
|
| + sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
|
| + VdbeComment((v, "output one row"));
|
| + sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v);
|
| + VdbeComment((v, "check abort flag"));
|
| + sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
| + VdbeComment((v, "reset accumulator"));
|
| +
|
| + /* Update the aggregate accumulators based on the content of
|
| + ** the current row
|
| + */
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + updateAccumulator(pParse, &sAggInfo);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
|
| + VdbeComment((v, "indicate data in accumulator"));
|
| +
|
| + /* End of the loop
|
| + */
|
| + if( groupBySort ){
|
| + sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
|
| + VdbeCoverage(v);
|
| + }else{
|
| + sqlite3WhereEnd(pWInfo);
|
| + sqlite3VdbeChangeToNoop(v, addrSortingIdx);
|
| + }
|
| +
|
| + /* Output the final row of result
|
| + */
|
| + sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
|
| + VdbeComment((v, "output final row"));
|
| +
|
| + /* Jump over the subroutines
|
| + */
|
| + sqlite3VdbeGoto(v, addrEnd);
|
| +
|
| + /* Generate a subroutine that outputs a single row of the result
|
| + ** set. This subroutine first looks at the iUseFlag. If iUseFlag
|
| + ** is less than or equal to zero, the subroutine is a no-op. If
|
| + ** the processing calls for the query to abort, this subroutine
|
| + ** increments the iAbortFlag memory location before returning in
|
| + ** order to signal the caller to abort.
|
| + */
|
| + addrSetAbort = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 1, iAbortFlag);
|
| + VdbeComment((v, "set abort flag"));
|
| + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
| + sqlite3VdbeResolveLabel(v, addrOutputRow);
|
| + addrOutputRow = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2);
|
| + VdbeCoverage(v);
|
| + VdbeComment((v, "Groupby result generator entry point"));
|
| + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
| + finalizeAggFunctions(pParse, &sAggInfo);
|
| + sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
|
| + selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
|
| + &sDistinct, pDest,
|
| + addrOutputRow+1, addrSetAbort);
|
| + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
| + VdbeComment((v, "end groupby result generator"));
|
| +
|
| + /* Generate a subroutine that will reset the group-by accumulator
|
| + */
|
| + sqlite3VdbeResolveLabel(v, addrReset);
|
| + resetAccumulator(pParse, &sAggInfo);
|
| + sqlite3VdbeAddOp1(v, OP_Return, regReset);
|
| +
|
| + } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
|
| + else {
|
| + ExprList *pDel = 0;
|
| +#ifndef SQLITE_OMIT_BTREECOUNT
|
| + Table *pTab;
|
| + if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
|
| + /* If isSimpleCount() returns a pointer to a Table structure, then
|
| + ** the SQL statement is of the form:
|
| + **
|
| + ** SELECT count(*) FROM <tbl>
|
| + **
|
| + ** where the Table structure returned represents table <tbl>.
|
| + **
|
| + ** This statement is so common that it is optimized specially. The
|
| + ** OP_Count instruction is executed either on the intkey table that
|
| + ** contains the data for table <tbl> or on one of its indexes. It
|
| + ** is better to execute the op on an index, as indexes are almost
|
| + ** always spread across less pages than their corresponding tables.
|
| + */
|
| + const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
| + const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */
|
| + Index *pIdx; /* Iterator variable */
|
| + KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
|
| + Index *pBest = 0; /* Best index found so far */
|
| + int iRoot = pTab->tnum; /* Root page of scanned b-tree */
|
| +
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
| +
|
| + /* Search for the index that has the lowest scan cost.
|
| + **
|
| + ** (2011-04-15) Do not do a full scan of an unordered index.
|
| + **
|
| + ** (2013-10-03) Do not count the entries in a partial index.
|
| + **
|
| + ** In practice the KeyInfo structure will not be used. It is only
|
| + ** passed to keep OP_OpenRead happy.
|
| + */
|
| + if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + if( pIdx->bUnordered==0
|
| + && pIdx->szIdxRow<pTab->szTabRow
|
| + && pIdx->pPartIdxWhere==0
|
| + && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
|
| + ){
|
| + pBest = pIdx;
|
| + }
|
| + }
|
| + if( pBest ){
|
| + iRoot = pBest->tnum;
|
| + pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
|
| + }
|
| +
|
| + /* Open a read-only cursor, execute the OP_Count, close the cursor. */
|
| + sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1);
|
| + if( pKeyInfo ){
|
| + sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
|
| + }
|
| + sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
|
| + sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
| + explainSimpleCount(pParse, pTab, pBest);
|
| + }else
|
| +#endif /* SQLITE_OMIT_BTREECOUNT */
|
| + {
|
| + /* Check if the query is of one of the following forms:
|
| + **
|
| + ** SELECT min(x) FROM ...
|
| + ** SELECT max(x) FROM ...
|
| + **
|
| + ** If it is, then ask the code in where.c to attempt to sort results
|
| + ** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
|
| + ** If where.c is able to produce results sorted in this order, then
|
| + ** add vdbe code to break out of the processing loop after the
|
| + ** first iteration (since the first iteration of the loop is
|
| + ** guaranteed to operate on the row with the minimum or maximum
|
| + ** value of x, the only row required).
|
| + **
|
| + ** A special flag must be passed to sqlite3WhereBegin() to slightly
|
| + ** modify behavior as follows:
|
| + **
|
| + ** + If the query is a "SELECT min(x)", then the loop coded by
|
| + ** where.c should not iterate over any values with a NULL value
|
| + ** for x.
|
| + **
|
| + ** + The optimizer code in where.c (the thing that decides which
|
| + ** index or indices to use) should place a different priority on
|
| + ** satisfying the 'ORDER BY' clause than it does in other cases.
|
| + ** Refer to code and comments in where.c for details.
|
| + */
|
| + ExprList *pMinMax = 0;
|
| + u8 flag = WHERE_ORDERBY_NORMAL;
|
| +
|
| + assert( p->pGroupBy==0 );
|
| + assert( flag==0 );
|
| + if( p->pHaving==0 ){
|
| + flag = minMaxQuery(&sAggInfo, &pMinMax);
|
| + }
|
| + assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) );
|
| +
|
| + if( flag ){
|
| + pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
|
| + pDel = pMinMax;
|
| + if( pMinMax && !db->mallocFailed ){
|
| + pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
|
| + pMinMax->a[0].pExpr->op = TK_COLUMN;
|
| + }
|
| + }
|
| +
|
| + /* This case runs if the aggregate has no GROUP BY clause. The
|
| + ** processing is much simpler since there is only a single row
|
| + ** of output.
|
| + */
|
| + resetAccumulator(pParse, &sAggInfo);
|
| + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
|
| + if( pWInfo==0 ){
|
| + sqlite3ExprListDelete(db, pDel);
|
| + goto select_end;
|
| + }
|
| + updateAccumulator(pParse, &sAggInfo);
|
| + assert( pMinMax==0 || pMinMax->nExpr==1 );
|
| + if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
| + sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
|
| + VdbeComment((v, "%s() by index",
|
| + (flag==WHERE_ORDERBY_MIN?"min":"max")));
|
| + }
|
| + sqlite3WhereEnd(pWInfo);
|
| + finalizeAggFunctions(pParse, &sAggInfo);
|
| + }
|
| +
|
| + sSort.pOrderBy = 0;
|
| + sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
|
| + selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
|
| + pDest, addrEnd, addrEnd);
|
| + sqlite3ExprListDelete(db, pDel);
|
| + }
|
| + sqlite3VdbeResolveLabel(v, addrEnd);
|
| +
|
| + } /* endif aggregate query */
|
| +
|
| + if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
|
| + explainTempTable(pParse, "DISTINCT");
|
| + }
|
| +
|
| + /* If there is an ORDER BY clause, then we need to sort the results
|
| + ** and send them to the callback one by one.
|
| + */
|
| + if( sSort.pOrderBy ){
|
| + explainTempTable(pParse,
|
| + sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
|
| + generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
|
| + }
|
| +
|
| + /* Jump here to skip this query
|
| + */
|
| + sqlite3VdbeResolveLabel(v, iEnd);
|
| +
|
| + /* The SELECT has been coded. If there is an error in the Parse structure,
|
| + ** set the return code to 1. Otherwise 0. */
|
| + rc = (pParse->nErr>0);
|
| +
|
| + /* Control jumps to here if an error is encountered above, or upon
|
| + ** successful coding of the SELECT.
|
| + */
|
| +select_end:
|
| + explainSetInteger(pParse->iSelectId, iRestoreSelectId);
|
| +
|
| + /* Identify column names if results of the SELECT are to be output.
|
| + */
|
| + if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){
|
| + generateColumnNames(pParse, pTabList, pEList);
|
| + }
|
| +
|
| + sqlite3DbFree(db, sAggInfo.aCol);
|
| + sqlite3DbFree(db, sAggInfo.aFunc);
|
| +#if SELECTTRACE_ENABLED
|
| + SELECTTRACE(1,pParse,p,("end processing\n"));
|
| + pParse->nSelectIndent--;
|
| +#endif
|
| + return rc;
|
| +}
|
| +
|
| +/************** End of select.c **********************************************/
|
| +/************** Begin file table.c *******************************************/
|
| +/*
|
| +** 2001 September 15
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains the sqlite3_get_table() and sqlite3_free_table()
|
| +** interface routines. These are just wrappers around the main
|
| +** interface routine of sqlite3_exec().
|
| +**
|
| +** These routines are in a separate files so that they will not be linked
|
| +** if they are not used.
|
| +*/
|
| +/* #include "sqliteInt.h" */
|
| +/* #include <stdlib.h> */
|
| +/* #include <string.h> */
|
| +
|
| +#ifndef SQLITE_OMIT_GET_TABLE
|
| +
|
| +/*
|
| +** This structure is used to pass data from sqlite3_get_table() through
|
| +** to the callback function is uses to build the result.
|
| +*/
|
| +typedef struct TabResult {
|
| + char **azResult; /* Accumulated output */
|
| + char *zErrMsg; /* Error message text, if an error occurs */
|
| + u32 nAlloc; /* Slots allocated for azResult[] */
|
| + u32 nRow; /* Number of rows in the result */
|
| + u32 nColumn; /* Number of columns in the result */
|
| + u32 nData; /* Slots used in azResult[]. (nRow+1)*nColumn */
|
| + int rc; /* Return code from sqlite3_exec() */
|
| +} TabResult;
|
| +
|
| +/*
|
| +** This routine is called once for each row in the result table. Its job
|
| +** is to fill in the TabResult structure appropriately, allocating new
|
| +** memory as necessary.
|
| +*/
|
| +static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
| + TabResult *p = (TabResult*)pArg; /* Result accumulator */
|
| + int need; /* Slots needed in p->azResult[] */
|
| + int i; /* Loop counter */
|
| + char *z; /* A single column of result */
|
| +
|
| + /* Make sure there is enough space in p->azResult to hold everything
|
| + ** we need to remember from this invocation of the callback.
|
| + */
|
| + if( p->nRow==0 && argv!=0 ){
|
| + need = nCol*2;
|
| + }else{
|
| + need = nCol;
|
| + }
|
| + if( p->nData + need > p->nAlloc ){
|
| + char **azNew;
|
| + p->nAlloc = p->nAlloc*2 + need;
|
| + azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
|
| + if( azNew==0 ) goto malloc_failed;
|
| + p->azResult = azNew;
|
| + }
|
| +
|
| + /* If this is the first row, then generate an extra row containing
|
| + ** the names of all columns.
|
| + */
|
| + if( p->nRow==0 ){
|
| + p->nColumn = nCol;
|
| + for(i=0; i<nCol; i++){
|
| + z = sqlite3_mprintf("%s", colv[i]);
|
| + if( z==0 ) goto malloc_failed;
|
| + p->azResult[p->nData++] = z;
|
| + }
|
| + }else if( (int)p->nColumn!=nCol ){
|
| + sqlite3_free(p->zErrMsg);
|
| + p->zErrMsg = sqlite3_mprintf(
|
| + "sqlite3_get_table() called with two or more incompatible queries"
|
| + );
|
| + p->rc = SQLITE_ERROR;
|
| + return 1;
|
| + }
|
| +
|
| + /* Copy over the row data
|
| + */
|
| + if( argv!=0 ){
|
| + for(i=0; i<nCol; i++){
|
| + if( argv[i]==0 ){
|
| + z = 0;
|
| + }else{
|
| + int n = sqlite3Strlen30(argv[i])+1;
|
| + z = sqlite3_malloc64( n );
|
| + if( z==0 ) goto malloc_failed;
|
| + memcpy(z, argv[i], n);
|
| + }
|
| + p->azResult[p->nData++] = z;
|
| + }
|
| + p->nRow++;
|
| + }
|
| + return 0;
|
| +
|
| +malloc_failed:
|
| + p->rc = SQLITE_NOMEM;
|
| + return 1;
|
| +}
|
| +
|
| +/*
|
| +** Query the database. But instead of invoking a callback for each row,
|
| +** malloc() for space to hold the result and return the entire results
|
| +** at the conclusion of the call.
|
| +**
|
| +** The result that is written to ***pazResult is held in memory obtained
|
| +** from malloc(). But the caller cannot free this memory directly.
|
| +** Instead, the entire table should be passed to sqlite3_free_table() when
|
| +** the calling procedure is finished using it.
|
| +*/
|
| +SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
|
| + sqlite3 *db, /* The database on which the SQL executes */
|
| + const char *zSql, /* The SQL to be executed */
|
| + char ***pazResult, /* Write the result table here */
|
| + int *pnRow, /* Write the number of rows in the result here */
|
| + int *pnColumn, /* Write the number of columns of result here */
|
| + char **pzErrMsg /* Write error messages here */
|
| +){
|
| + int rc;
|
| + TabResult res;
|
| +
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( !sqlite3SafetyCheckOk(db) || pazResult==0 ) return SQLITE_MISUSE_BKPT;
|
| +#endif
|
| + *pazResult = 0;
|
| + if( pnColumn ) *pnColumn = 0;
|
| + if( pnRow ) *pnRow = 0;
|
| + if( pzErrMsg ) *pzErrMsg = 0;
|
| + res.zErrMsg = 0;
|
| + res.nRow = 0;
|
| + res.nColumn = 0;
|
| + res.nData = 1;
|
| + res.nAlloc = 20;
|
| + res.rc = SQLITE_OK;
|
| + res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
|
| + if( res.azResult==0 ){
|
| + db->errCode = SQLITE_NOMEM;
|
| + return SQLITE_NOMEM;
|
| + }
|
| + res.azResult[0] = 0;
|
| + rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
|
| + assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
|
| + res.azResult[0] = SQLITE_INT_TO_PTR(res.nData);
|
| + if( (rc&0xff)==SQLITE_ABORT ){
|
| + sqlite3_free_table(&res.azResult[1]);
|
| + if( res.zErrMsg ){
|
| + if( pzErrMsg ){
|
| + sqlite3_free(*pzErrMsg);
|
| + *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
|
| + }
|
| + sqlite3_free(res.zErrMsg);
|
| + }
|
| + db->errCode = res.rc; /* Assume 32-bit assignment is atomic */
|
| + return res.rc;
|
| + }
|
| + sqlite3_free(res.zErrMsg);
|
| + if( rc!=SQLITE_OK ){
|
| + sqlite3_free_table(&res.azResult[1]);
|
| + return rc;
|
| + }
|
| + if( res.nAlloc>res.nData ){
|
| + char **azNew;
|
| + azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
|
| + if( azNew==0 ){
|
| + sqlite3_free_table(&res.azResult[1]);
|
| + db->errCode = SQLITE_NOMEM;
|
| + return SQLITE_NOMEM;
|
| + }
|
| + res.azResult = azNew;
|
| + }
|
| + *pazResult = &res.azResult[1];
|
| + if( pnColumn ) *pnColumn = res.nColumn;
|
| + if( pnRow ) *pnRow = res.nRow;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** This routine frees the space the sqlite3_get_table() malloced.
|
| +*/
|
| +SQLITE_API void SQLITE_STDCALL sqlite3_free_table(
|
| + char **azResult /* Result returned from sqlite3_get_table() */
|
| +){
|
| + if( azResult ){
|
| + int i, n;
|
| + azResult--;
|
| + assert( azResult!=0 );
|
| + n = SQLITE_PTR_TO_INT(azResult[0]);
|
| + for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); }
|
| + sqlite3_free(azResult);
|
| + }
|
| +}
|
| +
|
| +#endif /* SQLITE_OMIT_GET_TABLE */
|
| +
|
| +/************** End of table.c ***********************************************/
|
| +
|
| +/* Chain include. */
|
| +#include "sqlite3.05.c"
|
|
|