Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 4e2addad90399da9dbb35aa3c7301972fc9e7433 [file] [log] [blame]
drha43c8c82017-10-11 13:48:111/*
2** 2017-10-11
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11******************************************************************************
12**
13** This file contains an implementation of the "sqlite_dbpage" virtual table.
14**
15** The sqlite_dbpage virtual table is used to read or write whole raw
16** pages of the database file. The pager interface is used so that
17** uncommitted changes and changes recorded in the WAL file are correctly
18** retrieved.
drh34d0b1a2017-10-11 15:02:5319**
20** Usage example:
21**
22** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
23**
24** This is an eponymous virtual table so it does not need to be created before
25** use. The optional argument to the sqlite_dbpage() table name is the
26** schema for the database file that is to be read. The default schema is
27** "main".
28**
29** The data field of sqlite_dbpage table can be updated. The new
30** value must be a BLOB which is the correct page size, otherwise the
drh38b26d82024-09-10 12:09:0331** update fails. INSERT operations also work, and operate as if they
32** where REPLACE. The size of the database can be extended by INSERT-ing
33** new pages on the end.
34**
35** Rows may not be deleted. However, doing an INSERT to page number N
36** with NULL page data causes the N-th page and all subsequent pages to be
37** deleted and the database to be truncated.
drha43c8c82017-10-11 13:48:1138*/
39
40#include "sqliteInt.h" /* Requires access to internal data structures */
41#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
42 && !defined(SQLITE_OMIT_VIRTUALTABLE)
43
44typedef struct DbpageTable DbpageTable;
45typedef struct DbpageCursor DbpageCursor;
46
47struct DbpageCursor {
48 sqlite3_vtab_cursor base; /* Base class. Must be first */
49 int pgno; /* Current page number */
drh34d0b1a2017-10-11 15:02:5350 int mxPgno; /* Last page to visit on this scan */
drh3cd8aaa2017-10-25 19:18:3351 Pager *pPager; /* Pager being read/written */
52 DbPage *pPage1; /* Page 1 of the database */
53 int iDb; /* Index of database to analyze */
54 int szPage; /* Size of each page in bytes */
drha43c8c82017-10-11 13:48:1155};
56
57struct DbpageTable {
58 sqlite3_vtab base; /* Base class. Must be first */
59 sqlite3 *db; /* The database */
drh46a62af2024-10-02 18:54:4060 int iDbTrunc; /* Database to truncate */
61 Pgno pgnoTrunc; /* Size to truncate to */
drha43c8c82017-10-11 13:48:1162};
63
drh3cd8aaa2017-10-25 19:18:3364/* Columns */
65#define DBPAGE_COLUMN_PGNO 0
66#define DBPAGE_COLUMN_DATA 1
67#define DBPAGE_COLUMN_SCHEMA 2
68
69
drha43c8c82017-10-11 13:48:1170/*
71** Connect to or create a dbpagevfs virtual table.
72*/
73static int dbpageConnect(
74 sqlite3 *db,
75 void *pAux,
76 int argc, const char *const*argv,
77 sqlite3_vtab **ppVtab,
78 char **pzErr
79){
80 DbpageTable *pTab = 0;
81 int rc = SQLITE_OK;
drh3547e492022-12-23 14:49:2482 (void)pAux;
83 (void)argc;
84 (void)argv;
85 (void)pzErr;
drha43c8c82017-10-11 13:48:1186
drh2b1c2aa2020-01-07 19:45:4087 sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
drh0669d6e2023-04-03 15:01:3788 sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
drha43c8c82017-10-11 13:48:1189 rc = sqlite3_declare_vtab(db,
drh34d0b1a2017-10-11 15:02:5390 "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
drha43c8c82017-10-11 13:48:1191 if( rc==SQLITE_OK ){
92 pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
93 if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
94 }
95
96 assert( rc==SQLITE_OK || pTab==0 );
97 if( rc==SQLITE_OK ){
drha43c8c82017-10-11 13:48:1198 memset(pTab, 0, sizeof(DbpageTable));
99 pTab->db = db;
drha43c8c82017-10-11 13:48:11100 }
101
102 *ppVtab = (sqlite3_vtab*)pTab;
103 return rc;
104}
105
106/*
107** Disconnect from or destroy a dbpagevfs virtual table.
108*/
109static int dbpageDisconnect(sqlite3_vtab *pVtab){
110 sqlite3_free(pVtab);
111 return SQLITE_OK;
112}
113
114/*
115** idxNum:
116**
drh3cd8aaa2017-10-25 19:18:33117** 0 schema=main, full table scan
118** 1 schema=main, pgno=?1
119** 2 schema=?1, full table scan
120** 3 schema=?1, pgno=?2
drha43c8c82017-10-11 13:48:11121*/
122static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
drh34d0b1a2017-10-11 15:02:53123 int i;
drh3cd8aaa2017-10-25 19:18:33124 int iPlan = 0;
drh3547e492022-12-23 14:49:24125 (void)tab;
drh3cd8aaa2017-10-25 19:18:33126
127 /* If there is a schema= constraint, it must be honored. Report a
128 ** ridiculously large estimated cost if the schema= constraint is
129 ** unavailable
130 */
131 for(i=0; i<pIdxInfo->nConstraint; i++){
132 struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
133 if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue;
134 if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
135 if( !p->usable ){
drh20b3fc42018-11-16 20:18:07136 /* No solution. */
137 return SQLITE_CONSTRAINT;
drh3cd8aaa2017-10-25 19:18:33138 }
139 iPlan = 2;
140 pIdxInfo->aConstraintUsage[i].argvIndex = 1;
141 pIdxInfo->aConstraintUsage[i].omit = 1;
142 break;
143 }
144
145 /* If we reach this point, it means that either there is no schema=
146 ** constraint (in which case we use the "main" schema) or else the
147 ** schema constraint was accepted. Lower the estimated cost accordingly
148 */
149 pIdxInfo->estimatedCost = 1.0e6;
150
151 /* Check for constraints against pgno */
drh34d0b1a2017-10-11 15:02:53152 for(i=0; i<pIdxInfo->nConstraint; i++){
153 struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
154 if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
155 pIdxInfo->estimatedRows = 1;
156 pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
157 pIdxInfo->estimatedCost = 1.0;
drh3cd8aaa2017-10-25 19:18:33158 pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
drh34d0b1a2017-10-11 15:02:53159 pIdxInfo->aConstraintUsage[i].omit = 1;
drh3cd8aaa2017-10-25 19:18:33160 iPlan |= 1;
drh34d0b1a2017-10-11 15:02:53161 break;
162 }
163 }
drh3cd8aaa2017-10-25 19:18:33164 pIdxInfo->idxNum = iPlan;
165
drh34d0b1a2017-10-11 15:02:53166 if( pIdxInfo->nOrderBy>=1
167 && pIdxInfo->aOrderBy[0].iColumn<=0
168 && pIdxInfo->aOrderBy[0].desc==0
169 ){
170 pIdxInfo->orderByConsumed = 1;
171 }
drha43c8c82017-10-11 13:48:11172 return SQLITE_OK;
173}
174
175/*
176** Open a new dbpagevfs cursor.
177*/
178static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
179 DbpageCursor *pCsr;
180
181 pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
182 if( pCsr==0 ){
183 return SQLITE_NOMEM_BKPT;
184 }else{
185 memset(pCsr, 0, sizeof(DbpageCursor));
186 pCsr->base.pVtab = pVTab;
187 pCsr->pgno = -1;
188 }
189
190 *ppCursor = (sqlite3_vtab_cursor *)pCsr;
191 return SQLITE_OK;
192}
193
194/*
195** Close a dbpagevfs cursor.
196*/
197static int dbpageClose(sqlite3_vtab_cursor *pCursor){
198 DbpageCursor *pCsr = (DbpageCursor *)pCursor;
drh3cd8aaa2017-10-25 19:18:33199 if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
drha43c8c82017-10-11 13:48:11200 sqlite3_free(pCsr);
201 return SQLITE_OK;
202}
203
204/*
205** Move a dbpagevfs cursor to the next entry in the file.
206*/
207static int dbpageNext(sqlite3_vtab_cursor *pCursor){
208 int rc = SQLITE_OK;
209 DbpageCursor *pCsr = (DbpageCursor *)pCursor;
210 pCsr->pgno++;
211 return rc;
212}
213
214static int dbpageEof(sqlite3_vtab_cursor *pCursor){
215 DbpageCursor *pCsr = (DbpageCursor *)pCursor;
drh34d0b1a2017-10-11 15:02:53216 return pCsr->pgno > pCsr->mxPgno;
drha43c8c82017-10-11 13:48:11217}
218
drh3cd8aaa2017-10-25 19:18:33219/*
220** idxNum:
221**
222** 0 schema=main, full table scan
223** 1 schema=main, pgno=?1
224** 2 schema=?1, full table scan
225** 3 schema=?1, pgno=?2
226**
227** idxStr is not used
228*/
drha43c8c82017-10-11 13:48:11229static int dbpageFilter(
stephanb504aab2025-05-31 09:44:00230 sqlite3_vtab_cursor *pCursor,
drha43c8c82017-10-11 13:48:11231 int idxNum, const char *idxStr,
232 int argc, sqlite3_value **argv
233){
234 DbpageCursor *pCsr = (DbpageCursor *)pCursor;
235 DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
drh0503f2a2017-10-27 18:24:11236 int rc;
drh3cd8aaa2017-10-25 19:18:33237 sqlite3 *db = pTab->db;
238 Btree *pBt;
drha43c8c82017-10-11 13:48:11239
stephanb504aab2025-05-31 09:44:00240 UNUSED_PARAMETER(idxStr);
241 UNUSED_PARAMETER(argc);
242
drh3cd8aaa2017-10-25 19:18:33243 /* Default setting is no rows of result */
stephanb504aab2025-05-31 09:44:00244 pCsr->pgno = 1;
drh3cd8aaa2017-10-25 19:18:33245 pCsr->mxPgno = 0;
246
247 if( idxNum & 2 ){
248 const char *zSchema;
249 assert( argc>=1 );
250 zSchema = (const char*)sqlite3_value_text(argv[0]);
251 pCsr->iDb = sqlite3FindDbName(db, zSchema);
252 if( pCsr->iDb<0 ) return SQLITE_OK;
253 }else{
254 pCsr->iDb = 0;
255 }
256 pBt = db->aDb[pCsr->iDb].pBt;
drh2f9525b2023-02-05 00:24:42257 if( NEVER(pBt==0) ) return SQLITE_OK;
drh3cd8aaa2017-10-25 19:18:33258 pCsr->pPager = sqlite3BtreePager(pBt);
259 pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
260 pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
261 if( idxNum & 1 ){
262 assert( argc>(idxNum>>1) );
263 pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
264 if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
drh34d0b1a2017-10-11 15:02:53265 pCsr->pgno = 1;
266 pCsr->mxPgno = 0;
267 }else{
268 pCsr->mxPgno = pCsr->pgno;
269 }
270 }else{
drh3cd8aaa2017-10-25 19:18:33271 assert( pCsr->pgno==1 );
drh34d0b1a2017-10-11 15:02:53272 }
drh0503f2a2017-10-27 18:24:11273 if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
drh3cd8aaa2017-10-25 19:18:33274 rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0);
drha43c8c82017-10-11 13:48:11275 return rc;
276}
277
278static int dbpageColumn(
stephanb504aab2025-05-31 09:44:00279 sqlite3_vtab_cursor *pCursor,
280 sqlite3_context *ctx,
drha43c8c82017-10-11 13:48:11281 int i
282){
283 DbpageCursor *pCsr = (DbpageCursor *)pCursor;
drha43c8c82017-10-11 13:48:11284 int rc = SQLITE_OK;
285 switch( i ){
286 case 0: { /* pgno */
287 sqlite3_result_int(ctx, pCsr->pgno);
288 break;
289 }
290 case 1: { /* data */
291 DbPage *pDbPage = 0;
dan7985e052022-09-13 18:08:24292 if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){
293 /* The pending byte page. Assume it is zeroed out. Attempting to
294 ** request this page from the page is an SQLITE_CORRUPT error. */
295 sqlite3_result_zeroblob(ctx, pCsr->szPage);
296 }else{
297 rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
298 if( rc==SQLITE_OK ){
299 sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
300 SQLITE_TRANSIENT);
301 }
302 sqlite3PagerUnref(pDbPage);
drha43c8c82017-10-11 13:48:11303 }
drha43c8c82017-10-11 13:48:11304 break;
305 }
306 default: { /* schema */
307 sqlite3 *db = sqlite3_context_db_handle(ctx);
drh3cd8aaa2017-10-25 19:18:33308 sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC);
drha43c8c82017-10-11 13:48:11309 break;
310 }
311 }
dan5ca0b382022-09-12 20:02:33312 return rc;
drha43c8c82017-10-11 13:48:11313}
314
315static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
316 DbpageCursor *pCsr = (DbpageCursor *)pCursor;
317 *pRowid = pCsr->pgno;
318 return SQLITE_OK;
319}
320
drha683b052025-01-02 15:03:13321/*
322** Open write transactions. Since we do not know in advance which database
323** files will be written by the sqlite_dbpage virtual table, start a write
324** transaction on them all.
325**
326** Return SQLITE_OK if successful, or an SQLite error code otherwise.
327*/
328static int dbpageBeginTrans(DbpageTable *pTab){
329 sqlite3 *db = pTab->db;
330 int rc = SQLITE_OK;
331 int i;
332 for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
333 Btree *pBt = db->aDb[i].pBt;
334 if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
335 }
336 return rc;
337}
338
drh34d0b1a2017-10-11 15:02:53339static int dbpageUpdate(
340 sqlite3_vtab *pVtab,
341 int argc,
342 sqlite3_value **argv,
343 sqlite_int64 *pRowid
344){
345 DbpageTable *pTab = (DbpageTable *)pVtab;
mistachkinaca84e62017-11-10 12:41:21346 Pgno pgno;
drh34d0b1a2017-10-11 15:02:53347 DbPage *pDbPage = 0;
348 int rc = SQLITE_OK;
349 char *zErr = 0;
drh3cd8aaa2017-10-25 19:18:33350 int iDb;
351 Btree *pBt;
352 Pager *pPager;
353 int szPage;
drh38b26d82024-09-10 12:09:03354 int isInsert;
drh34d0b1a2017-10-11 15:02:53355
drh3547e492022-12-23 14:49:24356 (void)pRowid;
drha296cda2018-11-03 16:09:59357 if( pTab->db->flags & SQLITE_Defensive ){
358 zErr = "read-only";
359 goto update_fail;
360 }
drh34d0b1a2017-10-11 15:02:53361 if( argc==1 ){
362 zErr = "cannot delete";
363 goto update_fail;
364 }
drh882aba42024-09-09 18:45:58365 if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
366 pgno = (Pgno)sqlite3_value_int(argv[2]);
drh38b26d82024-09-10 12:09:03367 isInsert = 1;
drh882aba42024-09-09 18:45:58368 }else{
369 pgno = sqlite3_value_int(argv[0]);
370 if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
371 zErr = "cannot insert";
372 goto update_fail;
373 }
drh38b26d82024-09-10 12:09:03374 isInsert = 0;
drh34d0b1a2017-10-11 15:02:53375 }
drh882aba42024-09-09 18:45:58376 if( sqlite3_value_type(argv[4])==SQLITE_NULL ){
377 iDb = 0;
378 }else{
379 const char *zSchema = (const char*)sqlite3_value_text(argv[4]);
drh762946b2024-09-13 21:47:57380 iDb = sqlite3FindDbName(pTab->db, zSchema);
drh882aba42024-09-09 18:45:58381 if( iDb<0 ){
382 zErr = "no such schema";
383 goto update_fail;
384 }
drh3cd8aaa2017-10-25 19:18:33385 }
386 pBt = pTab->db->aDb[iDb].pBt;
drh882aba42024-09-09 18:45:58387 if( pgno<1 || NEVER(pBt==0) ){
drh3cd8aaa2017-10-25 19:18:33388 zErr = "bad page number";
389 goto update_fail;
390 }
391 szPage = sqlite3BtreeGetPageSize(pBt);
drh34d0b1a2017-10-11 15:02:53392 if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
drh3cd8aaa2017-10-25 19:18:33393 || sqlite3_value_bytes(argv[3])!=szPage
drh34d0b1a2017-10-11 15:02:53394 ){
drh3b3f2302024-10-02 16:55:27395 if( sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert && pgno>1 ){
396 /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and
397 ** all subsequent pages to be deleted. */
drh46a62af2024-10-02 18:54:40398 pTab->iDbTrunc = iDb;
drh4c138782025-03-20 11:47:39399 pTab->pgnoTrunc = pgno-1;
400 pgno = 1;
drh38b26d82024-09-10 12:09:03401 }else{
402 zErr = "bad page value";
403 goto update_fail;
404 }
drh34d0b1a2017-10-11 15:02:53405 }
drha683b052025-01-02 15:03:13406
407 if( dbpageBeginTrans(pTab)!=SQLITE_OK ){
408 zErr = "failed to open transaction";
409 goto update_fail;
410 }
411
drh3cd8aaa2017-10-25 19:18:33412 pPager = sqlite3BtreePager(pBt);
413 rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
drh34d0b1a2017-10-11 15:02:53414 if( rc==SQLITE_OK ){
drhc7dd9b62022-10-31 18:01:05415 const void *pData = sqlite3_value_blob(argv[3]);
drh38b26d82024-09-10 12:09:03416 if( (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){
417 unsigned char *aPage = sqlite3PagerGetData(pDbPage);
418 memcpy(aPage, pData, szPage);
drh46a62af2024-10-02 18:54:40419 pTab->pgnoTrunc = 0;
drh34d0b1a2017-10-11 15:02:53420 }
drhc5b9da32024-11-30 14:13:35421 }else{
422 pTab->pgnoTrunc = 0;
drh34d0b1a2017-10-11 15:02:53423 }
424 sqlite3PagerUnref(pDbPage);
425 return rc;
426
427update_fail:
drha0337902025-01-31 14:52:05428 pTab->pgnoTrunc = 0;
drh34d0b1a2017-10-11 15:02:53429 sqlite3_free(pVtab->zErrMsg);
430 pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
431 return SQLITE_ERROR;
432}
433
drh3cd8aaa2017-10-25 19:18:33434static int dbpageBegin(sqlite3_vtab *pVtab){
435 DbpageTable *pTab = (DbpageTable *)pVtab;
drh46a62af2024-10-02 18:54:40436 pTab->pgnoTrunc = 0;
drh38b26d82024-09-10 12:09:03437 return SQLITE_OK;
438}
439
440/* Invoke sqlite3PagerTruncate() as necessary, just prior to COMMIT
441*/
442static int dbpageSync(sqlite3_vtab *pVtab){
drh38b26d82024-09-10 12:09:03443 DbpageTable *pTab = (DbpageTable *)pVtab;
drh46a62af2024-10-02 18:54:40444 if( pTab->pgnoTrunc>0 ){
445 Btree *pBt = pTab->db->aDb[pTab->iDbTrunc].pBt;
446 Pager *pPager = sqlite3BtreePager(pBt);
drhbe2a40d2024-12-19 19:02:09447 sqlite3BtreeEnter(pBt);
drh2fb488d2024-12-17 14:32:37448 if( pTab->pgnoTrunc<sqlite3BtreeLastPage(pBt) ){
449 sqlite3PagerTruncateImage(pPager, pTab->pgnoTrunc);
450 }
drhbe2a40d2024-12-19 19:02:09451 sqlite3BtreeLeave(pBt);
drh38b26d82024-09-10 12:09:03452 }
drh46a62af2024-10-02 18:54:40453 pTab->pgnoTrunc = 0;
drh2f9525b2023-02-05 00:24:42454 return SQLITE_OK;
drh3cd8aaa2017-10-25 19:18:33455}
456
drh46a62af2024-10-02 18:54:40457/* Cancel any pending truncate.
458*/
drhc51dccb2024-10-03 09:53:44459static int dbpageRollbackTo(sqlite3_vtab *pVtab, int notUsed1){
drh46a62af2024-10-02 18:54:40460 DbpageTable *pTab = (DbpageTable *)pVtab;
461 pTab->pgnoTrunc = 0;
462 (void)notUsed1;
drh1e2834d2024-10-03 10:06:51463 return SQLITE_OK;
drh46a62af2024-10-02 18:54:40464}
drh3cd8aaa2017-10-25 19:18:33465
drha43c8c82017-10-11 13:48:11466/*
467** Invoke this routine to register the "dbpage" virtual table module
468*/
469int sqlite3DbpageRegister(sqlite3 *db){
470 static sqlite3_module dbpage_module = {
dan3835cf62025-01-02 15:27:15471 2, /* iVersion */
drha43c8c82017-10-11 13:48:11472 dbpageConnect, /* xCreate */
473 dbpageConnect, /* xConnect */
474 dbpageBestIndex, /* xBestIndex */
475 dbpageDisconnect, /* xDisconnect */
476 dbpageDisconnect, /* xDestroy */
477 dbpageOpen, /* xOpen - open a cursor */
478 dbpageClose, /* xClose - close a cursor */
479 dbpageFilter, /* xFilter - configure scan constraints */
480 dbpageNext, /* xNext - advance a cursor */
481 dbpageEof, /* xEof - check for end of scan */
482 dbpageColumn, /* xColumn - read data */
483 dbpageRowid, /* xRowid - read data */
drh34d0b1a2017-10-11 15:02:53484 dbpageUpdate, /* xUpdate */
drh3cd8aaa2017-10-25 19:18:33485 dbpageBegin, /* xBegin */
drh38b26d82024-09-10 12:09:03486 dbpageSync, /* xSync */
drha43c8c82017-10-11 13:48:11487 0, /* xCommit */
488 0, /* xRollback */
489 0, /* xFindMethod */
490 0, /* xRename */
491 0, /* xSavepoint */
492 0, /* xRelease */
dan3835cf62025-01-02 15:27:15493 dbpageRollbackTo, /* xRollbackTo */
drh19358872023-10-06 12:51:05494 0, /* xShadowName */
495 0 /* xIntegrity */
drha43c8c82017-10-11 13:48:11496 };
497 return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
498}
499#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
500int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
501#endif /* SQLITE_ENABLE_DBSTAT_VTAB */