Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -279,10 +279,11 @@ 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; @@ -356,18 +357,19 @@ }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( (aPragmaNames[mid].mPragFlag & PragFlag_NeedSchema)!=0 ){ + if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; } /* Jump to the appropriate pragma handler */ - switch( aPragmaNames[mid].ePragTyp ){ + switch( pPragma->ePragTyp ){ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) /* ** PRAGMA [database.]default_cache_size ** PRAGMA [database.]default_cache_size=N @@ -942,14 +944,13 @@ #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ #ifndef SQLITE_OMIT_FLAG_PRAGMAS case PragTyp_FLAG: { if( zRight==0 ){ - returnSingleInt(pParse, aPragmaNames[mid].zName, - (db->flags & aPragmaNames[mid].iArg)!=0 ); + returnSingleInt(pParse, pPragma->zName, (db->flags & pPragma->iArg)!=0 ); }else{ - int mask = aPragmaNames[mid].iArg; /* Mask of bits to set or clear. */ + 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); } @@ -1074,24 +1075,34 @@ Index *pIdx; Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx ){ int i; + int mx = pPragma->iArg ? pIdx->nColumn : pIdx->nKeyCol; pTab = pIdx->pTable; - sqlite3VdbeSetNumCols(v, 3); - pParse->nMem = 3; + sqlite3VdbeSetNumCols(v, 6); + pParse->nMem = 6; sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC); - for(i=0; inKeyCol; i++){ + sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC); + for(i=0; iaiColumn[i]; sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2); - assert( pTab->nCol>cnum ); - sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); + if( cnum<0 ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, 3); + }else{ + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0); + } + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4); + sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0); + sqlite3VdbeAddOp2(v, OP_Integer, inKeyCol, 6); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); } } } break; @@ -1100,21 +1111,26 @@ Table *pTab; int i; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ v = sqlite3GetVdbe(pParse); - sqlite3VdbeSetNumCols(v, 3); - pParse->nMem = 3; + sqlite3VdbeSetNumCols(v, 5); + pParse->nMem = 5; sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "origin", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "partial", SQLITE_STATIC); for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ + const char *azOrigin[] = { "c", "u", "pk" }; sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); + sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, azOrigin[pIdx->idxType], 0); + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->pPartIdxWhere!=0, 5); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } } } break; @@ -1680,13 +1696,13 @@ ** ** The user-version is not used internally by SQLite. It may be used by ** applications for any purpose. */ case PragTyp_HEADER_VALUE: { - int iCookie = aPragmaNames[mid].iArg; /* Which cookie to read or write */ + int iCookie = pPragma->iArg; /* Which cookie to read or write */ sqlite3VdbeUsesBtree(v, iDb); - if( zRight && (aPragmaNames[mid].mPragFlag & PragFlag_ReadOnly)==0 ){ + if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){ /* Write the specified cookie value */ static const VdbeOpList setCookie[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ { OP_Integer, 0, 1, 0}, /* 1 */ { OP_SetCookie, 0, 0, 1}, /* 2 */ @@ -1802,11 +1818,11 @@ ** 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( aPragmaNames[mid].ePragTyp==PragTyp_BUSY_TIMEOUT ); + assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT ); if( zRight ){ sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); } returnSingleInt(pParse, "timeout", db->busyTimeout); break; Index: src/pragma.h ================================================================== --- src/pragma.h +++ src/pragma.h @@ -234,10 +234,14 @@ /* iArg: */ 0 }, { /* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlag: */ PragFlag_NeedSchema, /* iArg: */ 0 }, + { /* zName: */ "index_xinfo", + /* ePragTyp: */ PragTyp_INDEX_INFO, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) { /* zName: */ "integrity_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, /* ePragFlag: */ PragFlag_NeedSchema, @@ -450,6 +454,6 @@ /* ePragTyp: */ PragTyp_FLAG, /* ePragFlag: */ 0, /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; -/* Number of pragmas: 58 on by default, 71 total. */ +/* Number of pragmas: 59 on by default, 72 total. */ Index: test/pragma.test ================================================================== --- test/pragma.test +++ test/pragma.test @@ -48,10 +48,34 @@ ifcapable !pragma { finish_test return } + +# Capture the output of a pragma in a TEMP table. +# +proc capture_pragma {db tabname sql} { + $db eval "DROP TABLE IF EXISTS temp.$tabname" + set once 1 + $db eval $sql x { + if {$once} { + set once 0 + set ins "INSERT INTO $tabname VALUES" + set crtab "CREATE TEMP TABLE $tabname " + set sep "(" + foreach col $x(*) { + append ins ${sep}\$x($col) + append crtab ${sep}\"$col\" + set sep , + } + append ins ) + append crtab ) + $db eval $crtab + } + $db eval $ins + } +} # Delete the preexisting database to avoid the special setup # that the "all.test" script does. # db close @@ -618,23 +642,27 @@ execsql { pragma foreign_key_list(t5); } } {} do_test pragma-6.4 { - execsql { + capture_pragma db out { pragma index_list(t3); } + db eval {SELECT seq, "name", "unique" FROM out ORDER BY seq} } {0 sqlite_autoindex_t3_1 1} } ifcapable {!foreignkey} { execsql {CREATE TABLE t3(a,b UNIQUE)} } do_test pragma-6.5.1 { execsql { CREATE INDEX t3i1 ON t3(a,b); + } + capture_pragma db out { pragma index_info(t3i1); } + db eval {SELECT seqno, cid, name FROM out ORDER BY seqno} } {0 0 a 1 1 b} do_test pragma-6.5.2 { execsql { pragma index_info(t3i1_bogus); } @@ -674,12 +702,14 @@ two text, three VARCHAR(45, 65) DEFAULT 'abcde', four REAL DEFAULT X'abcdef', five DEFAULT CURRENT_TIME ); - PRAGMA table_info(test_table); } + capture_pragma db out {PRAGMA table_info(test_table)} + db eval {SELECT cid, "name", type, "notnull", dflt_value, pk FROM out + ORDER BY cid} } [concat \ {0 one INT 1 -1 0} \ {1 two text 0 {} 0} \ {2 three {VARCHAR(45, 65)} 0 'abcde' 0} \ {3 four REAL 0 X'abcdef' 0} \ @@ -691,14 +721,13 @@ ifcapable schema_pragmas { do_test pragma-7.1.1 { # Make sure a pragma knows to read the schema if it needs to db close sqlite3 db test.db - execsql { - pragma index_list(t3); - } -} {0 t3i1 0 1 sqlite_autoindex_t3_1 1} + capture_pragma db out "PRAGMA index_list(t3)" + db eval {SELECT name, "origin" FROM out ORDER BY name DESC} +} {t3i1 c sqlite_autoindex_t3_1 u} do_test pragma-7.1.2 { execsql { pragma index_list(t3_bogus); } } {} @@ -1703,23 +1732,30 @@ CREATE INDEX i2 ON t1(c,d); CREATE TABLE t2(x INTEGER REFERENCES t1); } db2 eval {SELECT name FROM sqlite_master} } {t1 i1 i2 t2} -do_test 23.2 { +do_test 23.2a { db eval { DROP INDEX i2; CREATE INDEX i2 ON t1(c,d,b); } - db2 eval {PRAGMA index_info(i2)} -} {0 2 c 1 3 d 2 1 b} + capture_pragma db2 out {PRAGMA index_info(i2)} + db2 eval {SELECT cid, name, "desc", coll, "key", '|' FROM out ORDER BY seqno} +} {2 c 0 BINARY 1 | 3 d 0 BINARY 1 | 1 b 0 BINARY 1 |} +do_test 23.2b { +breakpoint; + capture_pragma db2 out {PRAGMA index_xinfo(i2)} + db2 eval {SELECT cid, name, "desc", coll, "key", '|' FROM out ORDER BY seqno} +} {2 c 0 BINARY 1 | 3 d 0 BINARY 1 | 1 b 0 BINARY 1 | -1 {} 0 BINARY 0 |} do_test 23.3 { db eval { CREATE INDEX i3 ON t1(d,b,c); } - db2 eval {PRAGMA index_list(t1)} -} {0 i3 0 1 i2 0 2 i1 0} + capture_pragma db2 out {PRAGMA index_list(t1)} + db2 eval {SELECT name, "unique", origin FROM out ORDER BY seq} +} {i3 0 c i2 0 c i1 0 c} do_test 23.4 { db eval { ALTER TABLE t1 ADD COLUMN e; } db2 eval { Index: tool/mkpragmatab.tcl ================================================================== --- tool/mkpragmatab.tcl +++ tool/mkpragmatab.tcl @@ -203,10 +203,18 @@ NAME: stats FLAG: NeedSchema IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: index_info + TYPE: INDEX_INFO + ARG: 0 + FLAG: NeedSchema + IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + + NAME: index_xinfo + TYPE: INDEX_INFO + ARG: 1 FLAG: NeedSchema IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: index_list FLAG: NeedSchema