1979 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1979 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			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"
 | |
| 
 | |
| /*
 | |
| ** Interpret the given string as a safety level.  Return 0 for OFF,
 | |
| ** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or 
 | |
| ** unrecognized string argument.  The FULL and EXTRA option is disallowed
 | |
| ** if the omitFull parameter it 1.
 | |
| **
 | |
| ** Note that the values returned are one less that the values that
 | |
| ** should be passed into sqlite3BtreeSetSafetyLevel().  The is done
 | |
| ** to support legacy SQL code.  The safety level used to be boolean
 | |
| ** and older scripts may have used numbers 0 for OFF and 1 for ON.
 | |
| */
 | |
| static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){
 | |
|                              /* 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); i++){
 | |
|     if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0
 | |
|      && (!omitFull || iValue[i]<=1)
 | |
|     ){
 | |
|       return iValue[i];
 | |
|     }
 | |
|   }
 | |
|   return dflt;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Interpret the given string as a boolean value.
 | |
| */
 | |
| 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.
 | |
| */
 | |
| 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.
 | |
| */
 | |
| 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},
 | |
|     };
 | |
|     VdbeOp *aOp;
 | |
|     sqlite3VdbeUsesBtree(v, iDb);
 | |
|     if( !zRight ){
 | |
|       setOneColumnName(v, "cache_size");
 | |
|       pParse->nMem += 2;
 | |
|       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);
 | |
|       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);
 | |
|     }
 | |
|     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) ){
 | |
|         sqlite3OomFault(db);
 | |
|       }
 | |
|     }
 | |
|     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_SetCookie,      0,         BTREE_INCR_VACUUM, 0},    /* 4 */
 | |
|         };
 | |
|         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);
 | |
|       }
 | |
|     }
 | |
|     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|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
 | |
|   ** 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;
 | |
| 
 | |
|     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 */
 | |
|       } 
 | |
|     }
 | |
|     {
 | |
|       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 */
 | |
| 
 | |
| #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_SetCookie,      0,  0,  0},    /* 1 */
 | |
|       };
 | |
|       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[] = {
 | |
|         { OP_Transaction,     0,  0,  0},    /* 0 */
 | |
|         { OP_ReadCookie,      0,  1,  0},    /* 1 */
 | |
|         { OP_ResultRow,       1,  1,  0}
 | |
|       };
 | |
|       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;
 | |
|       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 */
 | 
