Add the index_xinfo pragma which gives information about the fields that

reference the table PRIMARY KEY in addition to the index key fields.
Add extra columns "desc", "coll", and "key" to the index_info and index_xinfo
pragmas.  Add the "origin" and "partial" columns to the index_list pragma.

FossilOrigin-Name: 2743846cdba572f616f56d310633703b8b50959e
This commit is contained in:
drh 2015-02-06 01:07:15 +00:00
commit fe0e84c948
6 changed files with 104 additions and 39 deletions

View File

@ -1,5 +1,5 @@
C Fix\sa\smissing\smutex\sin\sSQLITE_TESTCTRL_IMPOSTER.
D 2015-02-04T20:56:49.607
C Add\sthe\sindex_xinfo\spragma\swhich\sgives\sinformation\sabout\sthe\sfields\sthat\nreference\sthe\stable\sPRIMARY\sKEY\sin\saddition\sto\sthe\sindex\skey\sfields.\nAdd\sextra\scolumns\s"desc",\s"coll",\sand\s"key"\sto\sthe\sindex_info\sand\sindex_xinfo\npragmas.\s\sAdd\sthe\s"origin"\sand\s"partial"\scolumns\sto\sthe\sindex_list\spragma.
D 2015-02-06T01:07:15.913
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 6b9e7677829aa94b9f30949656e27312aefb9a46
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -223,8 +223,8 @@ F src/parse.y c5d0d964f9ac023e8154cad512e54b0b6058e086
F src/pcache.c d210cf90d04365a74f85d21374dded65af67b0cb
F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
F src/pcache1.c 1e77432b40b7d3288327d9cdf399dcdfd2b6d3bf
F src/pragma.c 58044728a29a0240d14a850c3870e5ac3da436b2
F src/pragma.h 28804eae1286aab6f2ffa3682dc0b06b58c51834
F src/pragma.c ea0be138a99784b14e87bd4522fea40e7b979e9c
F src/pragma.h 09c89bca58e9a44de2116cc8272b8d454657129f
F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9
F src/printf.c 05edc41450d0eb2c05ef7db113bf32742ae65325
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
@ -787,7 +787,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test f9cc1dd987986c9d4949211c7a4ed55ec9aecba1
F test/pragma.test aa16dedfe01c02c8895169012f7dfde9c163f0d5
F test/pragma.test 6cf0f0ce4618e841457aa42745afda55ddbc95fe
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@ -1203,7 +1203,7 @@ F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f
F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkpragmatab.tcl 4b4e91f6b8fc45596686798b918999e923b91fc7
F tool/mkpragmatab.tcl 94f196c9961e0ca3513e29f57125a3197808be2d
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 9ef48e1748dce7b844f67e2450ff9dfeb0fb4ab5
F tool/mksqlite3c.tcl 6b8e572a90eb4e0086e3ba90d88b76c085919863
@ -1239,7 +1239,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P f30a057aeeac2b863493b6325325b075a76b9d21
R 7062d08c73f32c9ecf1fbd0a908460e5
P 71691c4be54b9ac6a35e35013f939b7d6fd4e6b8 3af19f84446ba5fc1ed754d0d73f6a6d7fb2f365
R 378ae50354305236538b7809f97882cb
T +closed 3af19f84446ba5fc1ed754d0d73f6a6d7fb2f365
U drh
Z 50e6879801fe010f0d0350ec5e4483dd
Z 9e4d57322f408f6027b92b8bd8c22512

View File

@ -1 +1 @@
71691c4be54b9ac6a35e35013f939b7d6fd4e6b8
2743846cdba572f616f56d310633703b8b50959e

View File

@ -281,6 +281,7 @@ void sqlite3Pragma(
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);
@ -358,14 +359,15 @@ void sqlite3Pragma(
}
}
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)
/*
@ -944,10 +946,9 @@ void sqlite3Pragma(
#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. */
@ -1076,20 +1077,30 @@ void sqlite3Pragma(
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; i<pIdx->nKeyCol; 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; i<mx; i++){
i16 cnum = pIdx->aiColumn[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, i<pIdx->nKeyCol, 6);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
}
}
}
@ -1102,17 +1113,22 @@ void sqlite3Pragma(
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);
}
}
}
@ -1682,9 +1698,9 @@ void sqlite3Pragma(
** 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 */
@ -1804,7 +1820,7 @@ void sqlite3Pragma(
** 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));
}

View File

@ -236,6 +236,10 @@ static const struct sPragmaNames {
/* 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",
@ -452,4 +456,4 @@ static const struct sPragmaNames {
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
#endif
};
/* Number of pragmas: 58 on by default, 71 total. */
/* Number of pragmas: 59 on by default, 72 total. */

View File

@ -51,6 +51,30 @@ ifcapable !pragma {
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.
#
@ -620,9 +644,10 @@ ifcapable {foreignkey} {
}
} {}
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} {
@ -631,8 +656,11 @@ ifcapable {!foreignkey} {
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 {
@ -676,8 +704,10 @@ do_test pragma-6.7 {
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} \
@ -693,10 +723,9 @@ 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);
@ -1705,19 +1734,26 @@ do_test 23.1 {
}
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;

View File

@ -205,6 +205,14 @@ set pragma_def {
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)