| Index: third_party/sqlite/src/src/pragma.c
|
| diff --git a/third_party/sqlite/src/src/pragma.c b/third_party/sqlite/src/src/pragma.c
|
| index 0d48057d210818c29d6558c617e10dc93c844b8d..b1775a4082a3a0135f962d8aa37d8809adcd6c4c 100644
|
| --- a/third_party/sqlite/src/src/pragma.c
|
| +++ b/third_party/sqlite/src/src/pragma.c
|
| @@ -32,8 +32,8 @@
|
|
|
| /*
|
| ** 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
|
| +** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
|
| +** unrecognized string argument. The FULL and EXTRA option is disallowed
|
| ** if the omitFull parameter it 1.
|
| **
|
| ** Note that the values returned are one less that the values that
|
| @@ -42,18 +42,21 @@
|
| ** 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};
|
| + /* 123456789 123456789 123 */
|
| + static const char zText[] = "onoffalseyestruextrafull";
|
| + static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 15, 20};
|
| + static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 5, 4};
|
| + static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 3, 2};
|
| + /* on no off false yes true extra full */
|
| 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 ){
|
| + for(i=0; i<ArraySize(iLength); i++){
|
| + if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0
|
| + && (!omitFull || iValue[i]<=1)
|
| + ){
|
| return iValue[i];
|
| }
|
| }
|
| @@ -160,29 +163,29 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
| #endif /* SQLITE_PAGER_PRAGMAS */
|
|
|
| /*
|
| -** Set the names of the first N columns to the values in azCol[]
|
| +** Set result column names for a pragma.
|
| */
|
| -static void setAllColumnNames(
|
| - Vdbe *v, /* The query under construction */
|
| - int N, /* Number of columns */
|
| - const char **azCol /* Names of columns */
|
| +static void setPragmaResultColumnNames(
|
| + Vdbe *v, /* The query under construction */
|
| + const PragmaName *pPragma /* The pragma */
|
| ){
|
| - int i;
|
| - sqlite3VdbeSetNumCols(v, N);
|
| - for(i=0; i<N; i++){
|
| - sqlite3VdbeSetColName(v, i, COLNAME_NAME, azCol[i], SQLITE_STATIC);
|
| + u8 n = pPragma->nPragCName;
|
| + sqlite3VdbeSetNumCols(v, n==0 ? 1 : n);
|
| + if( n==0 ){
|
| + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName, SQLITE_STATIC);
|
| + }else{
|
| + int i, j;
|
| + for(i=0, j=pPragma->iPragCName; i<n; i++, j++){
|
| + sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j], 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){
|
| +static void returnSingleInt(Vdbe *v, i64 value){
|
| sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8*)&value, P4_INT64);
|
| - setOneColumnName(v, zLabel);
|
| sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
| }
|
|
|
| @@ -191,12 +194,10 @@ static void returnSingleInt(Vdbe *v, const char *zLabel, i64 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);
|
| }
|
| }
|
| @@ -275,6 +276,26 @@ const char *sqlite3JournalModename(int eMode){
|
| }
|
|
|
| /*
|
| +** Locate a pragma in the aPragmaName[] array.
|
| +*/
|
| +static const PragmaName *pragmaLocate(const char *zName){
|
| + int upr, lwr, mid = 0, rc;
|
| + lwr = 0;
|
| + upr = ArraySize(aPragmaName)-1;
|
| + while( lwr<=upr ){
|
| + mid = (lwr+upr)/2;
|
| + rc = sqlite3_stricmp(zName, aPragmaName[mid].zName);
|
| + if( rc==0 ) break;
|
| + if( rc<0 ){
|
| + upr = mid - 1;
|
| + }else{
|
| + lwr = mid + 1;
|
| + }
|
| + }
|
| + return lwr>upr ? 0 : &aPragmaName[mid];
|
| +}
|
| +
|
| +/*
|
| ** Process a pragma statement.
|
| **
|
| ** Pragmas are of this form:
|
| @@ -302,12 +323,11 @@ void sqlite3Pragma(
|
| 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;
|
| + const PragmaName *pPragma; /* The pragma */
|
|
|
| if( v==0 ) return;
|
| sqlite3VdbeRunOnlyOnce(v);
|
| @@ -335,7 +355,7 @@ void sqlite3Pragma(
|
| }
|
|
|
| assert( pId2 );
|
| - zDb = pId2->n>0 ? pDb->zName : 0;
|
| + zDb = pId2->n>0 ? pDb->zDbSName : 0;
|
| if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
|
| goto pragma_out;
|
| }
|
| @@ -362,7 +382,9 @@ void sqlite3Pragma(
|
| db->busyHandler.nBusy = 0;
|
| rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
|
| if( rc==SQLITE_OK ){
|
| - returnSingleText(v, "result", aFcntl[0]);
|
| + sqlite3VdbeSetNumCols(v, 1);
|
| + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT);
|
| + returnSingleText(v, aFcntl[0]);
|
| sqlite3_free(aFcntl[0]);
|
| goto pragma_out;
|
| }
|
| @@ -377,26 +399,21 @@ void sqlite3Pragma(
|
| }
|
|
|
| /* 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];
|
| + pPragma = pragmaLocate(zLeft);
|
| + if( pPragma==0 ) goto pragma_out;
|
|
|
| /* Make sure the database schema is loaded if the pragma requires that */
|
| - if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
|
| + if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
|
| if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
| }
|
|
|
| + /* Register the result column names for pragmas that return results */
|
| + if( (pPragma->mPragFlg & PragFlg_NoColumns)==0
|
| + && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0)
|
| + ){
|
| + setPragmaResultColumnNames(v, pPragma);
|
| + }
|
| +
|
| /* Jump to the appropriate pragma handler */
|
| switch( pPragma->ePragTyp ){
|
|
|
| @@ -430,20 +447,20 @@ void sqlite3Pragma(
|
| { OP_Noop, 0, 0, 0},
|
| { OP_ResultRow, 1, 1, 0},
|
| };
|
| - int addr;
|
| + VdbeOp *aOp;
|
| 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);
|
| + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize));
|
| + aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn);
|
| + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
|
| + aOp[0].p1 = iDb;
|
| + aOp[1].p1 = iDb;
|
| + aOp[6].p1 = 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);
|
| + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, size);
|
| assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| pDb->pSchema->cache_size = size;
|
| sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
| @@ -467,14 +484,14 @@ void sqlite3Pragma(
|
| assert( pBt!=0 );
|
| if( !zRight ){
|
| int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
|
| - returnSingleInt(v, "page_size", size);
|
| + returnSingleInt(v, 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;
|
| + sqlite3OomFault(db);
|
| }
|
| }
|
| break;
|
| @@ -502,7 +519,7 @@ void sqlite3Pragma(
|
| }
|
| }
|
| b = sqlite3BtreeSecureDelete(pBt, b);
|
| - returnSingleInt(v, "secure_delete", b);
|
| + returnSingleInt(v, b);
|
| break;
|
| }
|
|
|
| @@ -534,8 +551,6 @@ void sqlite3Pragma(
|
| sqlite3AbsInt32(sqlite3Atoi(zRight)));
|
| }
|
| sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
|
| - sqlite3VdbeSetNumCols(v, 1);
|
| - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
|
| break;
|
| }
|
|
|
| @@ -581,7 +596,7 @@ void sqlite3Pragma(
|
| if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
|
| zRet = "exclusive";
|
| }
|
| - returnSingleText(v, "locking_mode", zRet);
|
| + returnSingleText(v, zRet);
|
| break;
|
| }
|
|
|
| @@ -594,7 +609,6 @@ void sqlite3Pragma(
|
| 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 */
|
| @@ -640,7 +654,7 @@ void sqlite3Pragma(
|
| if( iLimit<-1 ) iLimit = -1;
|
| }
|
| iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
|
| - returnSingleInt(v, "journal_size_limit", iLimit);
|
| + returnSingleInt(v, iLimit);
|
| break;
|
| }
|
|
|
| @@ -658,7 +672,7 @@ void sqlite3Pragma(
|
| Btree *pBt = pDb->pBt;
|
| assert( pBt!=0 );
|
| if( !zRight ){
|
| - returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
|
| + returnSingleInt(v, sqlite3BtreeGetAutoVacuum(pBt));
|
| }else{
|
| int eAuto = getAutoVacuum(zRight);
|
| assert( eAuto>=0 && eAuto<=2 );
|
| @@ -681,16 +695,18 @@ void sqlite3Pragma(
|
| { 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 */
|
| + { OP_SetCookie, 0, BTREE_INCR_VACUUM, 0}, /* 4 */
|
| };
|
| - 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);
|
| + VdbeOp *aOp;
|
| + int iAddr = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6));
|
| + aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
|
| + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
|
| + aOp[0].p1 = iDb;
|
| + aOp[1].p1 = iDb;
|
| + aOp[2].p2 = iAddr+4;
|
| + aOp[4].p1 = iDb;
|
| + aOp[4].p3 = eAuto - 1;
|
| sqlite3VdbeUsesBtree(v, iDb);
|
| }
|
| }
|
| @@ -735,7 +751,7 @@ void sqlite3Pragma(
|
| case PragTyp_CACHE_SIZE: {
|
| assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| if( !zRight ){
|
| - returnSingleInt(v, "cache_size", pDb->pSchema->cache_size);
|
| + returnSingleInt(v, pDb->pSchema->cache_size);
|
| }else{
|
| int size = sqlite3Atoi(zRight);
|
| pDb->pSchema->cache_size = size;
|
| @@ -769,7 +785,7 @@ void sqlite3Pragma(
|
| case PragTyp_CACHE_SPILL: {
|
| assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| if( !zRight ){
|
| - returnSingleInt(v, "cache_spill",
|
| + returnSingleInt(v,
|
| (db->flags & SQLITE_CacheSpill)==0 ? 0 :
|
| sqlite3BtreeSetSpillSize(pDb->pBt,0));
|
| }else{
|
| @@ -823,7 +839,7 @@ void sqlite3Pragma(
|
| rc = SQLITE_OK;
|
| #endif
|
| if( rc==SQLITE_OK ){
|
| - returnSingleInt(v, "mmap_size", sz);
|
| + returnSingleInt(v, sz);
|
| }else if( rc!=SQLITE_NOTFOUND ){
|
| pParse->nErr++;
|
| pParse->rc = rc;
|
| @@ -844,7 +860,7 @@ void sqlite3Pragma(
|
| */
|
| case PragTyp_TEMP_STORE: {
|
| if( !zRight ){
|
| - returnSingleInt(v, "temp_store", db->temp_store);
|
| + returnSingleInt(v, db->temp_store);
|
| }else{
|
| changeTempStorage(pParse, zRight);
|
| }
|
| @@ -863,7 +879,7 @@ void sqlite3Pragma(
|
| */
|
| case PragTyp_TEMP_STORE_DIRECTORY: {
|
| if( !zRight ){
|
| - returnSingleText(v, "temp_store_directory", sqlite3_temp_directory);
|
| + returnSingleText(v, sqlite3_temp_directory);
|
| }else{
|
| #ifndef SQLITE_OMIT_WSD
|
| if( zRight[0] ){
|
| @@ -907,7 +923,7 @@ void sqlite3Pragma(
|
| */
|
| case PragTyp_DATA_STORE_DIRECTORY: {
|
| if( !zRight ){
|
| - returnSingleText(v, "data_store_directory", sqlite3_data_directory);
|
| + returnSingleText(v, sqlite3_data_directory);
|
| }else{
|
| #ifndef SQLITE_OMIT_WSD
|
| if( zRight[0] ){
|
| @@ -946,7 +962,7 @@ void sqlite3Pragma(
|
| sqlite3_file *pFile = sqlite3PagerFile(pPager);
|
| sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
|
| &proxy_file_path);
|
| - returnSingleText(v, "lock_proxy_file", proxy_file_path);
|
| + returnSingleText(v, proxy_file_path);
|
| }else{
|
| Pager *pPager = sqlite3BtreePager(pDb->pBt);
|
| sqlite3_file *pFile = sqlite3PagerFile(pPager);
|
| @@ -969,7 +985,7 @@ void sqlite3Pragma(
|
|
|
| /*
|
| ** PRAGMA [schema.]synchronous
|
| - ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL
|
| + ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA
|
| **
|
| ** Return or set the local value of the synchronous flag. Changing
|
| ** the local value does not make changes to the disk file and the
|
| @@ -978,7 +994,7 @@ void sqlite3Pragma(
|
| */
|
| case PragTyp_SYNCHRONOUS: {
|
| if( !zRight ){
|
| - returnSingleInt(v, "synchronous", pDb->safety_level-1);
|
| + returnSingleInt(v, pDb->safety_level-1);
|
| }else{
|
| if( !db->autoCommit ){
|
| sqlite3ErrorMsg(pParse,
|
| @@ -987,6 +1003,7 @@ void sqlite3Pragma(
|
| int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
|
| if( iLevel==0 ) iLevel = 1;
|
| pDb->safety_level = iLevel;
|
| + pDb->bSyncSet = 1;
|
| setAllPagerFlags(db);
|
| }
|
| }
|
| @@ -997,7 +1014,8 @@ void sqlite3Pragma(
|
| #ifndef SQLITE_OMIT_FLAG_PRAGMAS
|
| case PragTyp_FLAG: {
|
| if( zRight==0 ){
|
| - returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
|
| + setPragmaResultColumnNames(v, pPragma);
|
| + returnSingleInt(v, (db->flags & pPragma->iArg)!=0 );
|
| }else{
|
| int mask = pPragma->iArg; /* Mask of bits to set or clear. */
|
| if( db->autoCommit==0 ){
|
| @@ -1023,7 +1041,7 @@ void sqlite3Pragma(
|
| ** 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);
|
| + sqlite3VdbeAddOp0(v, OP_Expire);
|
| setAllPagerFlags(db);
|
| }
|
| break;
|
| @@ -1045,18 +1063,14 @@ void sqlite3Pragma(
|
| */
|
| case PragTyp_TABLE_INFO: if( zRight ){
|
| Table *pTab;
|
| - pTab = sqlite3FindTable(db, zRight, zDb);
|
| + pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, 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) ){
|
| @@ -1070,12 +1084,13 @@ void sqlite3Pragma(
|
| }else{
|
| for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
|
| }
|
| + assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
|
| sqlite3VdbeMultiLoad(v, 1, "issisi",
|
| i-nHidden,
|
| pCol->zName,
|
| - pCol->zType ? pCol->zType : "",
|
| + sqlite3ColumnType(pCol,""),
|
| pCol->notNull ? 1 : 0,
|
| - pCol->zDflt,
|
| + pCol->pDflt ? pCol->pDflt->u.zToken : 0,
|
| k);
|
| sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
|
| }
|
| @@ -1084,26 +1099,23 @@ void sqlite3Pragma(
|
| 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));
|
| + pTab->szTabRow,
|
| + 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]));
|
| + pIdx->szIdxRow,
|
| + pIdx->aiRowLogEst[0]);
|
| sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
| }
|
| }
|
| @@ -1115,9 +1127,6 @@ void sqlite3Pragma(
|
| 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 ){
|
| @@ -1131,8 +1140,7 @@ void sqlite3Pragma(
|
| }
|
| pTab = pIdx->pTable;
|
| sqlite3CodeVerifySchema(pParse, iDb);
|
| - assert( pParse->nMem<=ArraySize(azCol) );
|
| - setAllColumnNames(v, pParse->nMem, azCol);
|
| + assert( pParse->nMem<=pPragma->nPragCName );
|
| for(i=0; i<mx; i++){
|
| i16 cnum = pIdx->aiColumn[i];
|
| sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum,
|
| @@ -1155,13 +1163,8 @@ void sqlite3Pragma(
|
| 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",
|
| @@ -1177,16 +1180,14 @@ void sqlite3Pragma(
|
| 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 );
|
| + assert( db->aDb[i].zDbSName!=0 );
|
| sqlite3VdbeMultiLoad(v, 1, "iss",
|
| i,
|
| - db->aDb[i].zName,
|
| + db->aDb[i].zDbSName,
|
| sqlite3BtreeGetFilename(db->aDb[i].pBt));
|
| sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
|
| }
|
| @@ -1194,11 +1195,9 @@ void sqlite3Pragma(
|
| 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);
|
| @@ -1214,17 +1213,11 @@ void sqlite3Pragma(
|
| 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++){
|
| @@ -1265,14 +1258,11 @@ void sqlite3Pragma(
|
| 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 ){
|
| @@ -1326,12 +1316,10 @@ void sqlite3Pragma(
|
| 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);
|
| + sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v);
|
| sqlite3VdbeGoto(v, addrOk);
|
| sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
| }else{
|
| @@ -1396,18 +1384,6 @@ void sqlite3Pragma(
|
| 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",
|
| @@ -1425,7 +1401,6 @@ void sqlite3Pragma(
|
|
|
| /* Initialize the VDBE program */
|
| pParse->nMem = 6;
|
| - setOneColumnName(v, "integrity_check");
|
|
|
| /* Set the maximum error count */
|
| mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
| @@ -1441,7 +1416,10 @@ void sqlite3Pragma(
|
| for(i=0; i<db->nDb; i++){
|
| HashElem *x;
|
| Hash *pTbls;
|
| + int *aRoot;
|
| int cnt = 0;
|
| + int mxIdx = 0;
|
| + int nIdx;
|
|
|
| if( OMIT_TEMPDB && i==1 ) continue;
|
| if( iDb>=0 && i!=iDb ) continue;
|
| @@ -1454,35 +1432,39 @@ void sqlite3Pragma(
|
|
|
| /* Do an integrity check of the B-Tree
|
| **
|
| - ** Begin by filling registers 2, 3, ... with the root pages numbers
|
| + ** Begin by finding 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)){
|
| + for(cnt=0, 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++;
|
| - }
|
| + if( HasRowid(pTab) ) cnt++;
|
| + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
|
| + if( nIdx>mxIdx ) mxIdx = nIdx;
|
| + }
|
| + aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
|
| + if( aRoot==0 ) break;
|
| + for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
| + Table *pTab = sqliteHashData(x);
|
| + Index *pIdx;
|
| + if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
|
| for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| - sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
|
| - VdbeComment((v, "%s", pIdx->zName));
|
| - cnt++;
|
| + aRoot[cnt++] = pIdx->tnum;
|
| }
|
| }
|
| + aRoot[cnt] = 0;
|
|
|
| /* Make sure sufficient number of registers have been allocated */
|
| - pParse->nMem = MAX( pParse->nMem, cnt+8 );
|
| + pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
|
|
|
| /* Do the b-tree integrity checks */
|
| - sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
|
| + sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
|
| 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),
|
| + sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
|
| P4_DYNAMIC);
|
| sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
|
| sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
|
| @@ -1512,7 +1494,8 @@ void sqlite3Pragma(
|
| 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);
|
| + assert( pParse->nMem>=8+j );
|
| + assert( sqlite3NoTempsInRange(pParse,1,7+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 */
|
| @@ -1604,10 +1587,23 @@ void sqlite3Pragma(
|
| #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);
|
| + {
|
| + static const int iLn = VDBE_OFFSET_LINENO(2);
|
| + static const VdbeOpList endCode[] = {
|
| + { OP_AddImm, 1, 0, 0}, /* 0 */
|
| + { OP_If, 1, 4, 0}, /* 1 */
|
| + { OP_String8, 0, 3, 0}, /* 2 */
|
| + { OP_ResultRow, 3, 1, 0}, /* 3 */
|
| + };
|
| + VdbeOp *aOp;
|
| +
|
| + aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
|
| + if( aOp ){
|
| + aOp[0].p2 = -mxErr;
|
| + aOp[2].p4type = P4_STATIC;
|
| + aOp[2].p4.z = "ok";
|
| + }
|
| + }
|
| }
|
| break;
|
| #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
| @@ -1656,7 +1652,7 @@ void sqlite3Pragma(
|
| 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);
|
| + returnSingleText(v, 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
|
| @@ -1691,7 +1687,9 @@ void sqlite3Pragma(
|
| ** PRAGMA [schema.]user_version
|
| ** PRAGMA [schema.]user_version = <integer>
|
| **
|
| - ** PRAGMA [schema.]freelist_count = <integer>
|
| + ** PRAGMA [schema.]freelist_count
|
| + **
|
| + ** PRAGMA [schema.]data_version
|
| **
|
| ** PRAGMA [schema.]application_id
|
| ** PRAGMA [schema.]application_id = <integer>
|
| @@ -1717,18 +1715,20 @@ void sqlite3Pragma(
|
| case PragTyp_HEADER_VALUE: {
|
| int iCookie = pPragma->iArg; /* Which cookie to read or write */
|
| sqlite3VdbeUsesBtree(v, iDb);
|
| - if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
|
| + if( zRight && (pPragma->mPragFlg & PragFlg_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 */
|
| + { OP_SetCookie, 0, 0, 0}, /* 1 */
|
| };
|
| - 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);
|
| + VdbeOp *aOp;
|
| + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie));
|
| + aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
|
| + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
|
| + aOp[0].p1 = iDb;
|
| + aOp[1].p1 = iDb;
|
| + aOp[1].p2 = iCookie;
|
| + aOp[1].p3 = sqlite3Atoi(zRight);
|
| }else{
|
| /* Read the specified cookie value */
|
| static const VdbeOpList readCookie[] = {
|
| @@ -1736,12 +1736,14 @@ void sqlite3Pragma(
|
| { 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);
|
| + VdbeOp *aOp;
|
| + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie));
|
| + aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0);
|
| + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
|
| + aOp[0].p1 = iDb;
|
| + aOp[1].p1 = iDb;
|
| + aOp[1].p3 = iCookie;
|
| + sqlite3VdbeReusable(v);
|
| }
|
| }
|
| break;
|
| @@ -1758,11 +1760,11 @@ void sqlite3Pragma(
|
| 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);
|
| }
|
| + sqlite3VdbeReusable(v);
|
| }
|
| break;
|
| #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
| @@ -1774,7 +1776,6 @@ void sqlite3Pragma(
|
| ** 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 ){
|
| @@ -1786,7 +1787,6 @@ void sqlite3Pragma(
|
| 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);
|
| @@ -1805,7 +1805,7 @@ void sqlite3Pragma(
|
| if( zRight ){
|
| sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
|
| }
|
| - returnSingleInt(v, "wal_autocheckpoint",
|
| + returnSingleInt(v,
|
| db->xWalCallback==sqlite3WalDefaultHook ?
|
| SQLITE_PTR_TO_INT(db->pWalArg) : 0);
|
| }
|
| @@ -1838,7 +1838,7 @@ void sqlite3Pragma(
|
| if( zRight ){
|
| sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
|
| }
|
| - returnSingleInt(v, "timeout", db->busyTimeout);
|
| + returnSingleInt(v, db->busyTimeout);
|
| break;
|
| }
|
|
|
| @@ -1858,7 +1858,7 @@ void sqlite3Pragma(
|
| if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
|
| sqlite3_soft_heap_limit64(N);
|
| }
|
| - returnSingleInt(v, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
|
| + returnSingleInt(v, sqlite3_soft_heap_limit64(-1));
|
| break;
|
| }
|
|
|
| @@ -1877,8 +1877,7 @@ void sqlite3Pragma(
|
| ){
|
| sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
|
| }
|
| - returnSingleInt(v, "threads",
|
| - sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
|
| + returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
|
| break;
|
| }
|
|
|
| @@ -1890,23 +1889,21 @@ void sqlite3Pragma(
|
| 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;
|
| + if( db->aDb[i].zDbSName==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,
|
| + }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0,
|
| SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
|
| zState = azLockName[j];
|
| }
|
| - sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState);
|
| + sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState);
|
| sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
|
| }
|
| break;
|
| @@ -1958,9 +1955,324 @@ void sqlite3Pragma(
|
|
|
| } /* End of the PRAGMA switch */
|
|
|
| + /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only
|
| + ** purpose is to execute assert() statements to verify that if the
|
| + ** PragFlg_NoColumns1 flag is set and the caller specified an argument
|
| + ** to the PRAGMA, the implementation has not added any OP_ResultRow
|
| + ** instructions to the VM. */
|
| + if( (pPragma->mPragFlg & PragFlg_NoColumns1) && zRight ){
|
| + sqlite3VdbeVerifyNoResultRow(v);
|
| + }
|
| +
|
| pragma_out:
|
| sqlite3DbFree(db, zLeft);
|
| sqlite3DbFree(db, zRight);
|
| }
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| +/*****************************************************************************
|
| +** Implementation of an eponymous virtual table that runs a pragma.
|
| +**
|
| +*/
|
| +typedef struct PragmaVtab PragmaVtab;
|
| +typedef struct PragmaVtabCursor PragmaVtabCursor;
|
| +struct PragmaVtab {
|
| + sqlite3_vtab base; /* Base class. Must be first */
|
| + sqlite3 *db; /* The database connection to which it belongs */
|
| + const PragmaName *pName; /* Name of the pragma */
|
| + u8 nHidden; /* Number of hidden columns */
|
| + u8 iHidden; /* Index of the first hidden column */
|
| +};
|
| +struct PragmaVtabCursor {
|
| + sqlite3_vtab_cursor base; /* Base class. Must be first */
|
| + sqlite3_stmt *pPragma; /* The pragma statement to run */
|
| + sqlite_int64 iRowid; /* Current rowid */
|
| + char *azArg[2]; /* Value of the argument and schema */
|
| +};
|
| +
|
| +/*
|
| +** Pragma virtual table module xConnect method.
|
| +*/
|
| +static int pragmaVtabConnect(
|
| + sqlite3 *db,
|
| + void *pAux,
|
| + int argc, const char *const*argv,
|
| + sqlite3_vtab **ppVtab,
|
| + char **pzErr
|
| +){
|
| + const PragmaName *pPragma = (const PragmaName*)pAux;
|
| + PragmaVtab *pTab = 0;
|
| + int rc;
|
| + int i, j;
|
| + char cSep = '(';
|
| + StrAccum acc;
|
| + char zBuf[200];
|
| +
|
| + UNUSED_PARAMETER(argc);
|
| + UNUSED_PARAMETER(argv);
|
| + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
| + sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x");
|
| + for(i=0, j=pPragma->iPragCName; i<pPragma->nPragCName; i++, j++){
|
| + sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]);
|
| + cSep = ',';
|
| + }
|
| + if( i==0 ){
|
| + sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName);
|
| + cSep = ',';
|
| + i++;
|
| + }
|
| + j = 0;
|
| + if( pPragma->mPragFlg & PragFlg_Result1 ){
|
| + sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN");
|
| + j++;
|
| + }
|
| + if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){
|
| + sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN");
|
| + j++;
|
| + }
|
| + sqlite3StrAccumAppend(&acc, ")", 1);
|
| + sqlite3StrAccumFinish(&acc);
|
| + assert( strlen(zBuf) < sizeof(zBuf)-1 );
|
| + rc = sqlite3_declare_vtab(db, zBuf);
|
| + if( rc==SQLITE_OK ){
|
| + pTab = (PragmaVtab*)sqlite3_malloc(sizeof(PragmaVtab));
|
| + if( pTab==0 ){
|
| + rc = SQLITE_NOMEM;
|
| + }else{
|
| + memset(pTab, 0, sizeof(PragmaVtab));
|
| + pTab->pName = pPragma;
|
| + pTab->db = db;
|
| + pTab->iHidden = i;
|
| + pTab->nHidden = j;
|
| + }
|
| + }else{
|
| + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
| + }
|
| +
|
| + *ppVtab = (sqlite3_vtab*)pTab;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Pragma virtual table module xDisconnect method.
|
| +*/
|
| +static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){
|
| + PragmaVtab *pTab = (PragmaVtab*)pVtab;
|
| + sqlite3_free(pTab);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/* Figure out the best index to use to search a pragma virtual table.
|
| +**
|
| +** There are not really any index choices. But we want to encourage the
|
| +** query planner to give == constraints on as many hidden parameters as
|
| +** possible, and especially on the first hidden parameter. So return a
|
| +** high cost if hidden parameters are unconstrained.
|
| +*/
|
| +static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
| + PragmaVtab *pTab = (PragmaVtab*)tab;
|
| + const struct sqlite3_index_constraint *pConstraint;
|
| + int i, j;
|
| + int seen[2];
|
| +
|
| + pIdxInfo->estimatedCost = (double)1;
|
| + if( pTab->nHidden==0 ){ return SQLITE_OK; }
|
| + pConstraint = pIdxInfo->aConstraint;
|
| + seen[0] = 0;
|
| + seen[1] = 0;
|
| + for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
| + if( pConstraint->usable==0 ) continue;
|
| + if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
| + if( pConstraint->iColumn < pTab->iHidden ) continue;
|
| + j = pConstraint->iColumn - pTab->iHidden;
|
| + assert( j < 2 );
|
| + seen[j] = i+1;
|
| + }
|
| + if( seen[0]==0 ){
|
| + pIdxInfo->estimatedCost = (double)2147483647;
|
| + pIdxInfo->estimatedRows = 2147483647;
|
| + return SQLITE_OK;
|
| + }
|
| + j = seen[0]-1;
|
| + pIdxInfo->aConstraintUsage[j].argvIndex = 1;
|
| + pIdxInfo->aConstraintUsage[j].omit = 1;
|
| + if( seen[1]==0 ) return SQLITE_OK;
|
| + pIdxInfo->estimatedCost = (double)20;
|
| + pIdxInfo->estimatedRows = 20;
|
| + j = seen[1]-1;
|
| + pIdxInfo->aConstraintUsage[j].argvIndex = 2;
|
| + pIdxInfo->aConstraintUsage[j].omit = 1;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/* Create a new cursor for the pragma virtual table */
|
| +static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
|
| + PragmaVtabCursor *pCsr;
|
| + pCsr = (PragmaVtabCursor*)sqlite3_malloc(sizeof(*pCsr));
|
| + if( pCsr==0 ) return SQLITE_NOMEM;
|
| + memset(pCsr, 0, sizeof(PragmaVtabCursor));
|
| + pCsr->base.pVtab = pVtab;
|
| + *ppCursor = &pCsr->base;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/* Clear all content from pragma virtual table cursor. */
|
| +static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){
|
| + int i;
|
| + sqlite3_finalize(pCsr->pPragma);
|
| + pCsr->pPragma = 0;
|
| + for(i=0; i<ArraySize(pCsr->azArg); i++){
|
| + sqlite3_free(pCsr->azArg[i]);
|
| + pCsr->azArg[i] = 0;
|
| + }
|
| +}
|
| +
|
| +/* Close a pragma virtual table cursor */
|
| +static int pragmaVtabClose(sqlite3_vtab_cursor *cur){
|
| + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)cur;
|
| + pragmaVtabCursorClear(pCsr);
|
| + sqlite3_free(pCsr);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/* Advance the pragma virtual table cursor to the next row */
|
| +static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){
|
| + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
|
| + int rc = SQLITE_OK;
|
| +
|
| + /* Increment the xRowid value */
|
| + pCsr->iRowid++;
|
| + assert( pCsr->pPragma );
|
| + if( SQLITE_ROW!=sqlite3_step(pCsr->pPragma) ){
|
| + rc = sqlite3_finalize(pCsr->pPragma);
|
| + pCsr->pPragma = 0;
|
| + pragmaVtabCursorClear(pCsr);
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Pragma virtual table module xFilter method.
|
| +*/
|
| +static int pragmaVtabFilter(
|
| + sqlite3_vtab_cursor *pVtabCursor,
|
| + int idxNum, const char *idxStr,
|
| + int argc, sqlite3_value **argv
|
| +){
|
| + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
|
| + PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
|
| + int rc;
|
| + int i, j;
|
| + StrAccum acc;
|
| + char *zSql;
|
| +
|
| + UNUSED_PARAMETER(idxNum);
|
| + UNUSED_PARAMETER(idxStr);
|
| + pragmaVtabCursorClear(pCsr);
|
| + j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1;
|
| + for(i=0; i<argc; i++, j++){
|
| + assert( j<ArraySize(pCsr->azArg) );
|
| + pCsr->azArg[j] = sqlite3_mprintf("%s", sqlite3_value_text(argv[i]));
|
| + if( pCsr->azArg[j]==0 ){
|
| + return SQLITE_NOMEM;
|
| + }
|
| + }
|
| + sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]);
|
| + sqlite3StrAccumAppendAll(&acc, "PRAGMA ");
|
| + if( pCsr->azArg[1] ){
|
| + sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]);
|
| + }
|
| + sqlite3StrAccumAppendAll(&acc, pTab->pName->zName);
|
| + if( pCsr->azArg[0] ){
|
| + sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]);
|
| + }
|
| + zSql = sqlite3StrAccumFinish(&acc);
|
| + if( zSql==0 ) return SQLITE_NOMEM;
|
| + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pPragma, 0);
|
| + sqlite3_free(zSql);
|
| + if( rc!=SQLITE_OK ){
|
| + pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
|
| + return rc;
|
| + }
|
| + return pragmaVtabNext(pVtabCursor);
|
| +}
|
| +
|
| +/*
|
| +** Pragma virtual table module xEof method.
|
| +*/
|
| +static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){
|
| + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
|
| + return (pCsr->pPragma==0);
|
| +}
|
| +
|
| +/* The xColumn method simply returns the corresponding column from
|
| +** the PRAGMA.
|
| +*/
|
| +static int pragmaVtabColumn(
|
| + sqlite3_vtab_cursor *pVtabCursor,
|
| + sqlite3_context *ctx,
|
| + int i
|
| +){
|
| + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
|
| + PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
|
| + if( i<pTab->iHidden ){
|
| + sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pPragma, i));
|
| + }else{
|
| + sqlite3_result_text(ctx, pCsr->azArg[i-pTab->iHidden],-1,SQLITE_TRANSIENT);
|
| + }
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Pragma virtual table module xRowid method.
|
| +*/
|
| +static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){
|
| + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
|
| + *p = pCsr->iRowid;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/* The pragma virtual table object */
|
| +static const sqlite3_module pragmaVtabModule = {
|
| + 0, /* iVersion */
|
| + 0, /* xCreate - create a table */
|
| + pragmaVtabConnect, /* xConnect - connect to an existing table */
|
| + pragmaVtabBestIndex, /* xBestIndex - Determine search strategy */
|
| + pragmaVtabDisconnect, /* xDisconnect - Disconnect from a table */
|
| + 0, /* xDestroy - Drop a table */
|
| + pragmaVtabOpen, /* xOpen - open a cursor */
|
| + pragmaVtabClose, /* xClose - close a cursor */
|
| + pragmaVtabFilter, /* xFilter - configure scan constraints */
|
| + pragmaVtabNext, /* xNext - advance a cursor */
|
| + pragmaVtabEof, /* xEof */
|
| + pragmaVtabColumn, /* xColumn - read data */
|
| + pragmaVtabRowid, /* xRowid - read data */
|
| + 0, /* xUpdate - write data */
|
| + 0, /* xBegin - begin transaction */
|
| + 0, /* xSync - sync transaction */
|
| + 0, /* xCommit - commit transaction */
|
| + 0, /* xRollback - rollback transaction */
|
| + 0, /* xFindFunction - function overloading */
|
| + 0, /* xRename - rename the table */
|
| + 0, /* xSavepoint */
|
| + 0, /* xRelease */
|
| + 0 /* xRollbackTo */
|
| +};
|
| +
|
| +/*
|
| +** Check to see if zTabName is really the name of a pragma. If it is,
|
| +** then register an eponymous virtual table for that pragma and return
|
| +** a pointer to the Module object for the new virtual table.
|
| +*/
|
| +Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){
|
| + const PragmaName *pName;
|
| + assert( sqlite3_strnicmp(zName, "pragma_", 7)==0 );
|
| + pName = pragmaLocate(zName+7);
|
| + if( pName==0 ) return 0;
|
| + if( (pName->mPragFlg & (PragFlg_Result0|PragFlg_Result1))==0 ) return 0;
|
| + assert( sqlite3HashFind(&db->aModule, zName)==0 );
|
| + return sqlite3VtabCreateModule(db, zName, &pragmaVtabModule, (void*)pName, 0);
|
| +}
|
| +
|
| +#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
|
| #endif /* SQLITE_OMIT_PRAGMA */
|
|
|