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 */ |