]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the sqlite_dbptr virtual table to the dbdata extension. For querying the links...
authordan <dan@noemail.net>
Thu, 18 Apr 2019 21:14:11 +0000 (21:14 +0000)
committerdan <dan@noemail.net>
Thu, 18 Apr 2019 21:14:11 +0000 (21:14 +0000)
FossilOrigin-Name: 3213a15f2133afbb0a4fec3b8f6e0eeca8c0befafd6658c41074e84f589d5d32

ext/misc/dbdata.c
manifest
manifest.uuid
test/dbdata.test

index c0ad8c1f9e46b7e40d6eb0f275f58fcdc0457d66..eb2bc01600651dac7ccb6cf83dc77f339a620d03 100644 (file)
@@ -23,6 +23,9 @@
 **       schema TEXT HIDDEN
 **     );
 **
+** IMPORTANT: THE VIRTUAL TABLE SCHEMA ABOVE IS SUBJECT TO CHANGE. IN THE
+** FUTURE NEW NON-HIDDEN COLUMNS MAY BE ADDED BETWEEN "value" AND "schema".
+**
 ** Each page of the database is inspected. If it cannot be interpreted as a
 ** b-tree page, or if it is a b-tree page containing 0 entries, the
 ** sqlite_dbdata table contains no rows for that page.  Otherwise, the table
 **
 ** This module requires that the "sqlite_dbpage" eponymous virtual table be
 ** available.
+**
+**
+**     CREATE TABLE sqlite_dbptr(
+**       pgno INTEGER,
+**       child INTEGER,
+**       schema TEXT HIDDEN
+**     );
 */
 #if !defined(SQLITEINT_H)
 #include "sqlite3ext.h"
@@ -67,6 +77,7 @@ SQLITE_EXTENSION_INIT1
 typedef struct DbdataTable DbdataTable;
 typedef struct DbdataCursor DbdataCursor;
 
+
 /* A cursor for the sqlite_dbdata table */
 struct DbdataCursor {
   sqlite3_vtab_cursor base;       /* Base class.  Must be first */
@@ -77,19 +88,22 @@ struct DbdataCursor {
   int nPage;                      /* Size of aPage[] in bytes */
   int nCell;                      /* Number of cells on aPage[] */
   int iCell;                      /* Current cell number */
+  int bOnePage;                   /* True to stop after one page */
+  sqlite3_int64 iRowid;
+
+  /* Only for the sqlite_dbdata table */
   u8 *pRec;                       /* Buffer containing current record */
   int nRec;                       /* Size of pRec[] in bytes */
   int nField;                     /* Number of fields in pRec */
   int iField;                     /* Current field number */
   sqlite3_int64 iIntkey;          /* Integer key value */
-
-  sqlite3_int64 iRowid;
 };
 
 /* The sqlite_dbdata table */
 struct DbdataTable {
   sqlite3_vtab base;              /* Base class.  Must be first */
   sqlite3 *db;                    /* The database connection */
+  int bPtr;                       /* True for sqlite3_dbptr table */
 };
 
 #define DBDATA_COLUMN_PGNO        0
@@ -98,6 +112,10 @@ struct DbdataTable {
 #define DBDATA_COLUMN_VALUE       3
 #define DBDATA_COLUMN_SCHEMA      4
 
+#define DBPTR_COLUMN_PGNO         0
+#define DBPTR_COLUMN_CHILD        1
+#define DBPTR_COLUMN_SCHEMA       2
+
 #define DBDATA_SCHEMA             \
       "CREATE TABLE x("           \
       "  pgno INTEGER,"           \
@@ -107,6 +125,13 @@ struct DbdataTable {
       "  schema TEXT HIDDEN"      \
       ")"
 
+#define DBPTR_SCHEMA              \
+      "CREATE TABLE x("           \
+      "  pgno INTEGER,"           \
+      "  child INTEGER,"          \
+      "  schema TEXT HIDDEN"      \
+      ")"
+
 /*
 ** Connect to the sqlite_dbdata virtual table.
 */
@@ -118,7 +143,7 @@ static int dbdataConnect(
   char **pzErr
 ){
   DbdataTable *pTab = 0;
-  int rc = sqlite3_declare_vtab(db, DBDATA_SCHEMA);
+  int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA);
 
   if( rc==SQLITE_OK ){
     pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable));
@@ -127,6 +152,7 @@ static int dbdataConnect(
     }else{
       memset(pTab, 0, sizeof(DbdataTable));
       pTab->db = db;
+      pTab->bPtr = (pAux!=0);
     }
   }
 
@@ -157,14 +183,16 @@ static int dbdataDisconnect(sqlite3_vtab *pVtab){
 ** position 1.
 */
 static int dbdataBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+  DbdataTable *pTab = (DbdataTable*)tab;
   int i;
   int iSchema = -1;
   int iPgno = -1;
+  int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA);
 
   for(i=0; i<pIdxInfo->nConstraint; i++){
     struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
     if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
-      if( p->iColumn==DBDATA_COLUMN_SCHEMA ){
+      if( p->iColumn==colSchema ){
         if( p->usable==0 ) return SQLITE_CONSTRAINT;
         iSchema = i;
       }
@@ -210,6 +238,7 @@ static void dbdataResetCursor(DbdataCursor *pCsr){
   pCsr->iPgno = 1;
   pCsr->iCell = 0;
   pCsr->iField = 0;
+  pCsr->bOnePage = 0;
 }
 
 /*
@@ -281,132 +310,152 @@ static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){
 ** Move a dbdata cursor to the next entry in the file.
 */
 static int dbdataNext(sqlite3_vtab_cursor *pCursor){
-  DbdataCursor *pCsr = (DbdataCursor *)pCursor;
+  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+  DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
 
   pCsr->iRowid++;
   while( 1 ){
     int rc;
+    int iOff = (pCsr->iPgno==1 ? 100 : 0);
 
     if( pCsr->aPage==0 ){
       rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage);
-      if( rc!=SQLITE_OK ) return rc;
-      pCsr->iCell = 0;
-      pCsr->nCell = get_uint16(&pCsr->aPage[pCsr->iPgno==1 ? 103 : 3]);
+      if( rc!=SQLITE_OK || pCsr->aPage==0 ) return rc;
+      pCsr->iCell = pTab->bPtr ? -2 : 0;
+      pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]);
     }
 
-    /* If there is no record loaded, load it now. */
-    if( pCsr->pRec==0 ){
-      int iOff = (pCsr->iPgno==1 ? 100 : 0);
-      int bHasRowid = 0;
-      int nPointer = 0;
-      sqlite3_int64 nPayload = 0;
-      sqlite3_int64 nHdr = 0;
-      int iHdr;
-      int U, X;
-      int nLocal;
-
-      switch( pCsr->aPage[iOff] ){
-        case 0x02:
-          nPointer = 4;
-          break;
-        case 0x0a:
-          break;
-        case 0x0d:
-          bHasRowid = 1;
-          break;
-        default:
-          pCsr->iCell = pCsr->nCell;
-          break;
+    if( pTab->bPtr ){
+      if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){
+        pCsr->iCell = pCsr->nCell;
       }
+      pCsr->iCell++;
       if( pCsr->iCell>=pCsr->nCell ){
         sqlite3_free(pCsr->aPage);
         pCsr->aPage = 0;
+        if( pCsr->bOnePage ) return SQLITE_OK;
+        pCsr->iPgno++;
+      }else{
         return SQLITE_OK;
       }
+    }else{
+      /* If there is no record loaded, load it now. */
+      if( pCsr->pRec==0 ){
+        int bHasRowid = 0;
+        int nPointer = 0;
+        sqlite3_int64 nPayload = 0;
+        sqlite3_int64 nHdr = 0;
+        int iHdr;
+        int U, X;
+        int nLocal;
+  
+        switch( pCsr->aPage[iOff] ){
+          case 0x02:
+            nPointer = 4;
+            break;
+          case 0x0a:
+            break;
+          case 0x0d:
+            bHasRowid = 1;
+            break;
+          default:
+            /* This is not a b-tree page with records on it. Continue. */
+            pCsr->iCell = pCsr->nCell;
+            break;
+        }
 
-      iOff += 8 + nPointer + pCsr->iCell*2;
-      iOff = get_uint16(&pCsr->aPage[iOff]);
-
-      /* For an interior node cell, skip past the child-page number */
-      iOff += nPointer;
-
-      /* Load the "byte of payload including overflow" field */
-      iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload);
-
-      /* If this is a leaf intkey cell, load the rowid */
-      if( bHasRowid ){
-        iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey);
-      }
-
-      /* Allocate space for payload */
-      pCsr->pRec = (u8*)sqlite3_malloc64(nPayload);
-      if( pCsr->pRec==0 ) return SQLITE_NOMEM;
-      pCsr->nRec = nPayload;
-
-      U = pCsr->nPage;
-      if( bHasRowid ){
-        X = U-35;
-      }else{
-        X = ((U-12)*64/255)-23;
-      }
-      if( nPayload<=X ){
-        nLocal = nPayload;
-      }else{
-        int M, K;
-        M = ((U-12)*32/255)-23;
-        K = M+((nPayload-M)%(U-4));
-        if( K<=X ){
-          nLocal = K;
+        if( pCsr->iCell>=pCsr->nCell ){
+          sqlite3_free(pCsr->aPage);
+          pCsr->aPage = 0;
+          if( pCsr->bOnePage ) return SQLITE_OK;
+          pCsr->iPgno++;
+          continue;
+        }
+  
+        iOff += 8 + nPointer + pCsr->iCell*2;
+        iOff = get_uint16(&pCsr->aPage[iOff]);
+  
+        /* For an interior node cell, skip past the child-page number */
+        iOff += nPointer;
+  
+        /* Load the "byte of payload including overflow" field */
+        iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload);
+  
+        /* If this is a leaf intkey cell, load the rowid */
+        if( bHasRowid ){
+          iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey);
+        }
+  
+        /* Allocate space for payload */
+        pCsr->pRec = (u8*)sqlite3_malloc64(nPayload);
+        if( pCsr->pRec==0 ) return SQLITE_NOMEM;
+        pCsr->nRec = nPayload;
+  
+        U = pCsr->nPage;
+        if( bHasRowid ){
+          X = U-35;
         }else{
-          nLocal = M;
+          X = ((U-12)*64/255)-23;
         }
-      }
-
-      /* Load the nLocal bytes of payload */
-      memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal);
-      iOff += nLocal;
-
-      /* Load content from overflow pages */
-      if( nPayload>nLocal ){
-        sqlite3_int64 nRem = nPayload - nLocal;
-        u32 pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
-        while( nRem>0 ){
-          u8 *aOvfl = 0;
-          int nOvfl = 0;
-          int nCopy;
-          rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl);
-          assert( rc!=SQLITE_OK || nOvfl==pCsr->nPage );
-          if( rc!=SQLITE_OK ) return rc;
-
-          nCopy = U-4;
-          if( nCopy>nRem ) nCopy = nRem;
-          memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy);
-          nRem -= nCopy;
-
-          sqlite3_free(aOvfl);
+        if( nPayload<=X ){
+          nLocal = nPayload;
+        }else{
+          int M, K;
+          M = ((U-12)*32/255)-23;
+          K = M+((nPayload-M)%(U-4));
+          if( K<=X ){
+            nLocal = K;
+          }else{
+            nLocal = M;
+          }
         }
+  
+        /* Load the nLocal bytes of payload */
+        memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal);
+        iOff += nLocal;
+  
+        /* Load content from overflow pages */
+        if( nPayload>nLocal ){
+          sqlite3_int64 nRem = nPayload - nLocal;
+          u32 pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
+          while( nRem>0 ){
+            u8 *aOvfl = 0;
+            int nOvfl = 0;
+            int nCopy;
+            rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl);
+            assert( rc!=SQLITE_OK || nOvfl==pCsr->nPage );
+            if( rc!=SQLITE_OK ) return rc;
+  
+            nCopy = U-4;
+            if( nCopy>nRem ) nCopy = nRem;
+            memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy);
+            nRem -= nCopy;
+  
+            sqlite3_free(aOvfl);
+          }
+        }
+  
+        /* Figure out how many fields in the record */
+        pCsr->nField = 0;
+        iHdr = dbdataGetVarint(pCsr->pRec, &nHdr);
+        while( iHdr<nHdr ){
+          sqlite3_int64 iDummy;
+          iHdr += dbdataGetVarint(&pCsr->pRec[iHdr], &iDummy);
+          pCsr->nField++;
+        }
+  
+        pCsr->iField = (bHasRowid ? -2 : -1);
       }
-
-      /* Figure out how many fields in the record */
-      pCsr->nField = 0;
-      iHdr = dbdataGetVarint(pCsr->pRec, &nHdr);
-      while( iHdr<nHdr ){
-        sqlite3_int64 iDummy;
-        iHdr += dbdataGetVarint(&pCsr->pRec[iHdr], &iDummy);
-        pCsr->nField++;
-      }
-
-      pCsr->iField = (bHasRowid ? -2 : -1);
+  
+      pCsr->iField++;
+      if( pCsr->iField<pCsr->nField ) return SQLITE_OK;
+  
+      /* Advance to the next cell. The next iteration of the loop will load
+      ** the record and so on. */
+      sqlite3_free(pCsr->pRec);
+      pCsr->pRec = 0;
+      pCsr->iCell++;
     }
-
-    pCsr->iField++;
-    if( pCsr->iField<pCsr->nField ) return SQLITE_OK;
-
-    /* Advance to the next cell. The next iteration of the loop will load
-    ** the record and so on. */
-    sqlite3_free(pCsr->pRec);
-    pCsr->pRec = 0;
-    pCsr->iCell++;
   }
 
   assert( !"can't get here" );
@@ -440,6 +489,7 @@ static int dbdataFilter(
   }
   if( idxNum & 0x02 ){
     pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]);
+    pCsr->bOnePage = 1;
   }
 
   rc = sqlite3_prepare_v2(pTab->db, 
@@ -533,34 +583,54 @@ static int dbdataColumn(
   int i
 ){
   DbdataCursor *pCsr = (DbdataCursor*)pCursor;
-  switch( i ){
-    case DBDATA_COLUMN_PGNO:
-      sqlite3_result_int64(ctx, pCsr->iPgno);
-      break;
-    case DBDATA_COLUMN_CELL:
-      sqlite3_result_int(ctx, pCsr->iCell);
-      break;
-    case DBDATA_COLUMN_FIELD:
-      sqlite3_result_int(ctx, pCsr->iField);
-      break;
-    case DBDATA_COLUMN_VALUE: {
-      if( pCsr->iField<0 ){
-        sqlite3_result_int64(ctx, pCsr->iIntkey);
-      }else{
-        int iHdr;
-        sqlite3_int64 iType;
-        sqlite3_int64 iOff;
-        int i;
-        iHdr = dbdataGetVarint(pCsr->pRec, &iOff);
-        for(i=0; i<pCsr->iField; i++){
-          iHdr += dbdataGetVarint(&pCsr->pRec[iHdr], &iType);
-          iOff += dbdataValueBytes(iType);
+  DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
+  if( pTab->bPtr ){
+    switch( i ){
+      case DBPTR_COLUMN_PGNO:
+        sqlite3_result_int64(ctx, pCsr->iPgno);
+        break;
+      case DBPTR_COLUMN_CHILD: {
+        int iOff = pCsr->iPgno==1 ? 100 : 0;
+        if( pCsr->iCell<0 ){
+          iOff += 8;
+        }else{
+          iOff += 12 + pCsr->iCell*2;
+          iOff = get_uint16(&pCsr->aPage[iOff]);
         }
-        dbdataGetVarint(&pCsr->pRec[iHdr], &iType);
-
-        dbdataValue(ctx, iType, &pCsr->pRec[iOff]);
+        sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff]));
+        break;
+      }
+    }
+  }else{
+    switch( i ){
+      case DBDATA_COLUMN_PGNO:
+        sqlite3_result_int64(ctx, pCsr->iPgno);
+        break;
+      case DBDATA_COLUMN_CELL:
+        sqlite3_result_int(ctx, pCsr->iCell);
+        break;
+      case DBDATA_COLUMN_FIELD:
+        sqlite3_result_int(ctx, pCsr->iField);
+        break;
+      case DBDATA_COLUMN_VALUE: {
+        if( pCsr->iField<0 ){
+          sqlite3_result_int64(ctx, pCsr->iIntkey);
+        }else{
+          int iHdr;
+          sqlite3_int64 iType;
+          sqlite3_int64 iOff;
+          int i;
+          iHdr = dbdataGetVarint(pCsr->pRec, &iOff);
+          for(i=0; i<pCsr->iField; i++){
+            iHdr += dbdataGetVarint(&pCsr->pRec[iHdr], &iType);
+            iOff += dbdataValueBytes(iType);
+          }
+          dbdataGetVarint(&pCsr->pRec[iHdr], &iType);
+
+          dbdataValue(ctx, iType, &pCsr->pRec[iOff]);
+        }
+        break;
       }
-      break;
     }
   }
   return SQLITE_OK;
@@ -604,7 +674,12 @@ static int sqlite3DbdataRegister(sqlite3 *db){
     0,                            /* xRollbackTo */
     0                             /* xShadowName */
   };
-  return sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0);
+
+  int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0);
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1);
+  }
+  return rc;
 }
 
 #ifdef _WIN32
index 59bdc64972bacf35729a9e3116215f632ede165b..d6a2b045e82cfc9c7f76bfda0be63b29ff16392a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sexperimental\sdbdata\sextension.
-D 2019-04-17T21:17:22.795
+C Add\sthe\ssqlite_dbptr\svirtual\stable\sto\sthe\sdbdata\sextension.\sFor\squerying\sthe\slinks\sbetween\sb-tree\spages.
+D 2019-04-18T21:14:11.260
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -284,7 +284,7 @@ F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c8
 F ext/misc/completion.c cec672d40604075bb341a7f11ac48393efdcd90a979269b8fe7977ea62d0547f
 F ext/misc/compress.c dd4f8a6d0baccff3c694757db5b430f3bbd821d8686d1fc24df55cf9f035b189
 F ext/misc/csv.c 7f047aeb68f5802e7ce6639292095d622a488bb43526ed04810e0649faa71ceb
-F ext/misc/dbdata.c 436a7883a7f1455c5d2853bd927c5ac31826b21c6e16ca11a21d7262d25ff838
+F ext/misc/dbdata.c 20d85d7d7503817a5f9ac7d93c4ae7bf5fcc40570a77adc417acab0500058c99
 F ext/misc/dbdump.c baf6e37447c9d6968417b1cd34cbedb0b0ab3f91b5329501d8a8d5be3287c336
 F ext/misc/eval.c 4b4757592d00fd32e44c7a067e6a0e4839c81a4d57abc4131ee7806d1be3104e
 F ext/misc/explain.c d5c12962d79913ef774b297006872af1fccda388f61a11d37758f9179a09551f
@@ -787,7 +787,7 @@ F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee
 F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
 F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
 F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
-F test/dbdata.test 6e791619d18e0cff2c79392de980ca0594368cdaa05326f043f866beb0c82614
+F test/dbdata.test 573fa3347744863e47d011e4e8e9b87c6795ba92a759bf5d5c68da975900ddd4
 F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
 F test/dbfuzz001.test e32d14465f1c77712896fda6a1ccc0f037b481c191c1696a9c44f6c9e4964faf
 F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
@@ -1820,10 +1820,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 7ac500fb5abfe1ad60f2ffdcc8fbe5ccc1c641bbeed53f00940e9ff78788e53d
-R 9b65ccecf461800383c04a268416aaa8
-T *branch * dbdata
-T *sym-dbdata *
-T -sym-trunk *
+P a3ab58832935e1399ecc7e4d8daefa3a6afa6b301792ce7176bc5d7c173510fb
+R 901e9e476021499846a29c847f49c578
 U dan
-Z f99e8e6e33bab5d12ccf1d6f1a7cae6f
+Z e0c2ac18f5bd53328c7a0485e8c7ef97
index dc49ef98d80564c23e273dcd2234fa20c0d70bda..6ee3f97f4ef9db11e0a688a4e9f1d6fc476d7a45 100644 (file)
@@ -1 +1 @@
-a3ab58832935e1399ecc7e4d8daefa3a6afa6b301792ce7176bc5d7c173510fb
\ No newline at end of file
+3213a15f2133afbb0a4fec3b8f6e0eeca8c0befafd6658c41074e84f589d5d32
\ No newline at end of file
index c4412a5de9a2f356d337fdb82a8c18d4a3dd9058..5a0df5dc8605f716e5321d073d54f62d1b7ef28b 100644 (file)
@@ -43,12 +43,62 @@ do_execsql_test 1.1 {
   2 1  1 'ten'
 }
 
-set big [string repeat big 2000]
+breakpoint
 do_execsql_test 1.2 {
+  SELECT pgno, cell, field, quote(value) FROM sqlite_dbdata;
+} {
+  1 0 -1 1 
+  1 0 0 'table' 
+  1 0 1 'T1' 
+  1 0 2 'T1' 
+  1 0 3 2 
+  1 0 4 {'CREATE TABLE T1(a, b)'}
+  2 0 -1 5 
+  2 0  0 'v' 
+  2 0  1 'five' 
+  2 1 -1 10 
+  2 1  0 'x' 
+  2 1  1 'ten'
+}
+
+set big [string repeat big 2000]
+do_execsql_test 1.3 {
   INSERT INTO t1 VALUES(NULL, $big);
   SELECT value FROM sqlite_dbdata WHERE pgno=2 AND cell=2 AND field=1;
 } $big
 
+#-------------------------------------------------------------------------
+reset_db
+db enable_load_extension 1
+db eval { SELECT load_extension('../dbdata') }
+
+do_execsql_test 2.0 {
+  CREATE TABLE t1(a);
+  CREATE INDEX i1 ON t1(a);
+  WITH s(i) AS (
+    SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10
+  )
+  INSERT INTO t1 SELECT randomblob(900) FROM s;
+}
+
+do_execsql_test 2.1 {
+  SELECT * FROM sqlite_dbptr WHERE pgno=2;
+} {
+  2 25   2 6   2 7   2 9   2 11   2 13   2 15   2 17   2 19   2 21
+}
+
+do_execsql_test 2.2 {
+  SELECT * FROM sqlite_dbptr WHERE pgno=3;
+} {
+  3 24   3 23
+}
+
+do_execsql_test 2.3 {
+  SELECT * FROM sqlite_dbptr
+} {
+  2 25   2 6   2 7   2 9   2 11   2 13   2 15   2 17   2 19   2 21
+  3 24   3 23
+}
 
 
 finish_test