Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/sqlite/src/src/dbpage.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* | - | ||||||||||||||||||
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. | - | ||||||||||||||||||
19 | ** | - | ||||||||||||||||||
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 | - | ||||||||||||||||||
31 | ** update fails. Rows may not be deleted or inserted. | - | ||||||||||||||||||
32 | */ | - | ||||||||||||||||||
33 | - | |||||||||||||||||||
34 | #include "sqliteInt.h" /* Requires access to internal data structures */ | - | ||||||||||||||||||
35 | #if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ | - | ||||||||||||||||||
36 | && !defined(SQLITE_OMIT_VIRTUALTABLE) | - | ||||||||||||||||||
37 | - | |||||||||||||||||||
38 | typedef struct DbpageTable DbpageTable; | - | ||||||||||||||||||
39 | typedef struct DbpageCursor DbpageCursor; | - | ||||||||||||||||||
40 | - | |||||||||||||||||||
41 | struct DbpageCursor { | - | ||||||||||||||||||
42 | sqlite3_vtab_cursor base; /* Base class. Must be first */ | - | ||||||||||||||||||
43 | int pgno; /* Current page number */ | - | ||||||||||||||||||
44 | int mxPgno; /* Last page to visit on this scan */ | - | ||||||||||||||||||
45 | Pager *pPager; /* Pager being read/written */ | - | ||||||||||||||||||
46 | DbPage *pPage1; /* Page 1 of the database */ | - | ||||||||||||||||||
47 | int iDb; /* Index of database to analyze */ | - | ||||||||||||||||||
48 | int szPage; /* Size of each page in bytes */ | - | ||||||||||||||||||
49 | }; | - | ||||||||||||||||||
50 | - | |||||||||||||||||||
51 | struct DbpageTable { | - | ||||||||||||||||||
52 | sqlite3_vtab base; /* Base class. Must be first */ | - | ||||||||||||||||||
53 | sqlite3 *db; /* The database */ | - | ||||||||||||||||||
54 | }; | - | ||||||||||||||||||
55 | - | |||||||||||||||||||
56 | /* Columns */ | - | ||||||||||||||||||
57 | #define DBPAGE_COLUMN_PGNO 0 | - | ||||||||||||||||||
58 | #define DBPAGE_COLUMN_DATA 1 | - | ||||||||||||||||||
59 | #define DBPAGE_COLUMN_SCHEMA 2 | - | ||||||||||||||||||
60 | - | |||||||||||||||||||
61 | - | |||||||||||||||||||
62 | - | |||||||||||||||||||
63 | /* | - | ||||||||||||||||||
64 | ** Connect to or create a dbpagevfs virtual table. | - | ||||||||||||||||||
65 | */ | - | ||||||||||||||||||
66 | static int dbpageConnect( | - | ||||||||||||||||||
67 | sqlite3 *db, | - | ||||||||||||||||||
68 | void *pAux, | - | ||||||||||||||||||
69 | int argc, const char *const*argv, | - | ||||||||||||||||||
70 | sqlite3_vtab **ppVtab, | - | ||||||||||||||||||
71 | char **pzErr | - | ||||||||||||||||||
72 | ){ | - | ||||||||||||||||||
73 | DbpageTable *pTab = 0; | - | ||||||||||||||||||
74 | int rc = SQLITE_OK; | - | ||||||||||||||||||
75 | - | |||||||||||||||||||
76 | rc = sqlite3_declare_vtab(db, | - | ||||||||||||||||||
77 | "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); | - | ||||||||||||||||||
78 | if( rc==SQLITE_OK ){
| 0-5 | ||||||||||||||||||
79 | pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); | - | ||||||||||||||||||
80 | if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; never executed: rc = 7;
| 0-5 | ||||||||||||||||||
81 | } executed 5 times by 1 test: end of block Executed by:
| 5 | ||||||||||||||||||
82 | - | |||||||||||||||||||
83 | assert( rc==SQLITE_OK || pTab==0 ); | - | ||||||||||||||||||
84 | if( rc==SQLITE_OK ){
| 0-5 | ||||||||||||||||||
85 | memset(pTab, 0, sizeof(DbpageTable)); | - | ||||||||||||||||||
86 | pTab->db = db; | - | ||||||||||||||||||
87 | } executed 5 times by 1 test: end of block Executed by:
| 5 | ||||||||||||||||||
88 | - | |||||||||||||||||||
89 | *ppVtab = (sqlite3_vtab*)pTab; | - | ||||||||||||||||||
90 | return rc; executed 5 times by 1 test: return rc; Executed by:
| 5 | ||||||||||||||||||
91 | } | - | ||||||||||||||||||
92 | - | |||||||||||||||||||
93 | /* | - | ||||||||||||||||||
94 | ** Disconnect from or destroy a dbpagevfs virtual table. | - | ||||||||||||||||||
95 | */ | - | ||||||||||||||||||
96 | static int dbpageDisconnect(sqlite3_vtab *pVtab){ | - | ||||||||||||||||||
97 | sqlite3_free(pVtab); | - | ||||||||||||||||||
98 | return SQLITE_OK; executed 5 times by 1 test: return 0; Executed by:
| 5 | ||||||||||||||||||
99 | } | - | ||||||||||||||||||
100 | - | |||||||||||||||||||
101 | /* | - | ||||||||||||||||||
102 | ** idxNum: | - | ||||||||||||||||||
103 | ** | - | ||||||||||||||||||
104 | ** 0 schema=main, full table scan | - | ||||||||||||||||||
105 | ** 1 schema=main, pgno=?1 | - | ||||||||||||||||||
106 | ** 2 schema=?1, full table scan | - | ||||||||||||||||||
107 | ** 3 schema=?1, pgno=?2 | - | ||||||||||||||||||
108 | */ | - | ||||||||||||||||||
109 | static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ | - | ||||||||||||||||||
110 | int i; | - | ||||||||||||||||||
111 | int iPlan = 0; | - | ||||||||||||||||||
112 | - | |||||||||||||||||||
113 | /* If there is a schema= constraint, it must be honored. Report a | - | ||||||||||||||||||
114 | ** ridiculously large estimated cost if the schema= constraint is | - | ||||||||||||||||||
115 | ** unavailable | - | ||||||||||||||||||
116 | */ | - | ||||||||||||||||||
117 | for(i=0; i<pIdxInfo->nConstraint; i++){
| 11-21 | ||||||||||||||||||
118 | struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; | - | ||||||||||||||||||
119 | if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue; executed 13 times by 1 test: continue; Executed by:
| 8-13 | ||||||||||||||||||
120 | if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; never executed: continue;
| 0-8 | ||||||||||||||||||
121 | if( !p->usable ){
| 1-7 | ||||||||||||||||||
122 | /* No solution. Use the default SQLITE_BIG_DBL cost */ | - | ||||||||||||||||||
123 | pIdxInfo->estimatedRows = 0x7fffffff; | - | ||||||||||||||||||
124 | return SQLITE_OK; executed 1 time by 1 test: return 0; Executed by:
| 1 | ||||||||||||||||||
125 | } | - | ||||||||||||||||||
126 | iPlan = 2; | - | ||||||||||||||||||
127 | pIdxInfo->aConstraintUsage[i].argvIndex = 1; | - | ||||||||||||||||||
128 | pIdxInfo->aConstraintUsage[i].omit = 1; | - | ||||||||||||||||||
129 | break; executed 7 times by 1 test: break; Executed by:
| 7 | ||||||||||||||||||
130 | } | - | ||||||||||||||||||
131 | - | |||||||||||||||||||
132 | /* If we reach this point, it means that either there is no schema= | - | ||||||||||||||||||
133 | ** constraint (in which case we use the "main" schema) or else the | - | ||||||||||||||||||
134 | ** schema constraint was accepted. Lower the estimated cost accordingly | - | ||||||||||||||||||
135 | */ | - | ||||||||||||||||||
136 | pIdxInfo->estimatedCost = 1.0e6; | - | ||||||||||||||||||
137 | - | |||||||||||||||||||
138 | /* Check for constraints against pgno */ | - | ||||||||||||||||||
139 | for(i=0; i<pIdxInfo->nConstraint; i++){
| 3-20 | ||||||||||||||||||
140 | struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; | - | ||||||||||||||||||
141 | if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
| 0-20 | ||||||||||||||||||
142 | pIdxInfo->estimatedRows = 1; | - | ||||||||||||||||||
143 | pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; | - | ||||||||||||||||||
144 | pIdxInfo->estimatedCost = 1.0; | - | ||||||||||||||||||
145 | pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
| 4-11 | ||||||||||||||||||
146 | pIdxInfo->aConstraintUsage[i].omit = 1; | - | ||||||||||||||||||
147 | iPlan |= 1; | - | ||||||||||||||||||
148 | break; executed 15 times by 1 test: break; Executed by:
| 15 | ||||||||||||||||||
149 | } | - | ||||||||||||||||||
150 | } executed 5 times by 1 test: end of block Executed by:
| 5 | ||||||||||||||||||
151 | pIdxInfo->idxNum = iPlan; | - | ||||||||||||||||||
152 | - | |||||||||||||||||||
153 | if( pIdxInfo->nOrderBy>=1
| 2-16 | ||||||||||||||||||
154 | && pIdxInfo->aOrderBy[0].iColumn<=0
| 0-2 | ||||||||||||||||||
155 | && pIdxInfo->aOrderBy[0].desc==0
| 0-2 | ||||||||||||||||||
156 | ){ | - | ||||||||||||||||||
157 | pIdxInfo->orderByConsumed = 1; | - | ||||||||||||||||||
158 | } executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||||||||||||||
159 | return SQLITE_OK; executed 18 times by 1 test: return 0; Executed by:
| 18 | ||||||||||||||||||
160 | } | - | ||||||||||||||||||
161 | - | |||||||||||||||||||
162 | /* | - | ||||||||||||||||||
163 | ** Open a new dbpagevfs cursor. | - | ||||||||||||||||||
164 | */ | - | ||||||||||||||||||
165 | static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ | - | ||||||||||||||||||
166 | DbpageCursor *pCsr; | - | ||||||||||||||||||
167 | - | |||||||||||||||||||
168 | pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor)); | - | ||||||||||||||||||
169 | if( pCsr==0 ){
| 0-18 | ||||||||||||||||||
170 | return SQLITE_NOMEM_BKPT; never executed: return 7; | 0 | ||||||||||||||||||
171 | }else{ | - | ||||||||||||||||||
172 | memset(pCsr, 0, sizeof(DbpageCursor)); | - | ||||||||||||||||||
173 | pCsr->base.pVtab = pVTab; | - | ||||||||||||||||||
174 | pCsr->pgno = -1; | - | ||||||||||||||||||
175 | } executed 18 times by 1 test: end of block Executed by:
| 18 | ||||||||||||||||||
176 | - | |||||||||||||||||||
177 | *ppCursor = (sqlite3_vtab_cursor *)pCsr; | - | ||||||||||||||||||
178 | return SQLITE_OK; executed 18 times by 1 test: return 0; Executed by:
| 18 | ||||||||||||||||||
179 | } | - | ||||||||||||||||||
180 | - | |||||||||||||||||||
181 | /* | - | ||||||||||||||||||
182 | ** Close a dbpagevfs cursor. | - | ||||||||||||||||||
183 | */ | - | ||||||||||||||||||
184 | static int dbpageClose(sqlite3_vtab_cursor *pCursor){ | - | ||||||||||||||||||
185 | DbpageCursor *pCsr = (DbpageCursor *)pCursor; | - | ||||||||||||||||||
186 | if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1); executed 18 times by 1 test: sqlite3PagerUnrefPageOne(pCsr->pPage1); Executed by:
| 0-18 | ||||||||||||||||||
187 | sqlite3_free(pCsr); | - | ||||||||||||||||||
188 | return SQLITE_OK; executed 18 times by 1 test: return 0; Executed by:
| 18 | ||||||||||||||||||
189 | } | - | ||||||||||||||||||
190 | - | |||||||||||||||||||
191 | /* | - | ||||||||||||||||||
192 | ** Move a dbpagevfs cursor to the next entry in the file. | - | ||||||||||||||||||
193 | */ | - | ||||||||||||||||||
194 | static int dbpageNext(sqlite3_vtab_cursor *pCursor){ | - | ||||||||||||||||||
195 | int rc = SQLITE_OK; | - | ||||||||||||||||||
196 | DbpageCursor *pCsr = (DbpageCursor *)pCursor; | - | ||||||||||||||||||
197 | pCsr->pgno++; | - | ||||||||||||||||||
198 | return rc; executed 16 times by 1 test: return rc; Executed by:
| 16 | ||||||||||||||||||
199 | } | - | ||||||||||||||||||
200 | - | |||||||||||||||||||
201 | static int dbpageEof(sqlite3_vtab_cursor *pCursor){ | - | ||||||||||||||||||
202 | DbpageCursor *pCsr = (DbpageCursor *)pCursor; | - | ||||||||||||||||||
203 | return pCsr->pgno > pCsr->mxPgno; executed 35 times by 1 test: return pCsr->pgno > pCsr->mxPgno; Executed by:
| 35 | ||||||||||||||||||
204 | } | - | ||||||||||||||||||
205 | - | |||||||||||||||||||
206 | /* | - | ||||||||||||||||||
207 | ** idxNum: | - | ||||||||||||||||||
208 | ** | - | ||||||||||||||||||
209 | ** 0 schema=main, full table scan | - | ||||||||||||||||||
210 | ** 1 schema=main, pgno=?1 | - | ||||||||||||||||||
211 | ** 2 schema=?1, full table scan | - | ||||||||||||||||||
212 | ** 3 schema=?1, pgno=?2 | - | ||||||||||||||||||
213 | ** | - | ||||||||||||||||||
214 | ** idxStr is not used | - | ||||||||||||||||||
215 | */ | - | ||||||||||||||||||
216 | static int dbpageFilter( | - | ||||||||||||||||||
217 | sqlite3_vtab_cursor *pCursor, | - | ||||||||||||||||||
218 | int idxNum, const char *idxStr, | - | ||||||||||||||||||
219 | int argc, sqlite3_value **argv | - | ||||||||||||||||||
220 | ){ | - | ||||||||||||||||||
221 | DbpageCursor *pCsr = (DbpageCursor *)pCursor; | - | ||||||||||||||||||
222 | DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; | - | ||||||||||||||||||
223 | int rc; | - | ||||||||||||||||||
224 | sqlite3 *db = pTab->db; | - | ||||||||||||||||||
225 | Btree *pBt; | - | ||||||||||||||||||
226 | - | |||||||||||||||||||
227 | /* Default setting is no rows of result */ | - | ||||||||||||||||||
228 | pCsr->pgno = 1; | - | ||||||||||||||||||
229 | pCsr->mxPgno = 0; | - | ||||||||||||||||||
230 | - | |||||||||||||||||||
231 | if( idxNum & 2 ){
| 8-11 | ||||||||||||||||||
232 | const char *zSchema; | - | ||||||||||||||||||
233 | assert( argc>=1 ); | - | ||||||||||||||||||
234 | zSchema = (const char*)sqlite3_value_text(argv[0]); | - | ||||||||||||||||||
235 | pCsr->iDb = sqlite3FindDbName(db, zSchema); | - | ||||||||||||||||||
236 | if( pCsr->iDb<0 ) return SQLITE_OK; never executed: return 0;
| 0-8 | ||||||||||||||||||
237 | }else{ executed 8 times by 1 test: end of block Executed by:
| 8 | ||||||||||||||||||
238 | pCsr->iDb = 0; | - | ||||||||||||||||||
239 | } executed 11 times by 1 test: end of block Executed by:
| 11 | ||||||||||||||||||
240 | pBt = db->aDb[pCsr->iDb].pBt; | - | ||||||||||||||||||
241 | if( pBt==0 ) return SQLITE_OK; never executed: return 0;
| 0-19 | ||||||||||||||||||
242 | pCsr->pPager = sqlite3BtreePager(pBt); | - | ||||||||||||||||||
243 | pCsr->szPage = sqlite3BtreeGetPageSize(pBt); | - | ||||||||||||||||||
244 | pCsr->mxPgno = sqlite3BtreeLastPage(pBt); | - | ||||||||||||||||||
245 | if( idxNum & 1 ){
| 3-16 | ||||||||||||||||||
246 | assert( argc>(idxNum>>1) ); | - | ||||||||||||||||||
247 | pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]); | - | ||||||||||||||||||
248 | if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
| 1-15 | ||||||||||||||||||
249 | pCsr->pgno = 1; | - | ||||||||||||||||||
250 | pCsr->mxPgno = 0; | - | ||||||||||||||||||
251 | }else{ executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||||||||||||||
252 | pCsr->mxPgno = pCsr->pgno; | - | ||||||||||||||||||
253 | } executed 14 times by 1 test: end of block Executed by:
| 14 | ||||||||||||||||||
254 | }else{ | - | ||||||||||||||||||
255 | assert( pCsr->pgno==1 ); | - | ||||||||||||||||||
256 | } executed 3 times by 1 test: end of block Executed by:
| 3 | ||||||||||||||||||
257 | if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1); executed 1 time by 1 test: sqlite3PagerUnrefPageOne(pCsr->pPage1); Executed by:
| 1-18 | ||||||||||||||||||
258 | rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0); | - | ||||||||||||||||||
259 | return rc; executed 19 times by 1 test: return rc; Executed by:
| 19 | ||||||||||||||||||
260 | } | - | ||||||||||||||||||
261 | - | |||||||||||||||||||
262 | static int dbpageColumn( | - | ||||||||||||||||||
263 | sqlite3_vtab_cursor *pCursor, | - | ||||||||||||||||||
264 | sqlite3_context *ctx, | - | ||||||||||||||||||
265 | int i | - | ||||||||||||||||||
266 | ){ | - | ||||||||||||||||||
267 | DbpageCursor *pCsr = (DbpageCursor *)pCursor; | - | ||||||||||||||||||
268 | int rc = SQLITE_OK; | - | ||||||||||||||||||
269 | switch( i ){ | - | ||||||||||||||||||
270 | case 0: { /* pgno */ executed 22 times by 1 test: case 0: Executed by:
| 22 | ||||||||||||||||||
271 | sqlite3_result_int(ctx, pCsr->pgno); | - | ||||||||||||||||||
272 | break; executed 22 times by 1 test: break; Executed by:
| 22 | ||||||||||||||||||
273 | } | - | ||||||||||||||||||
274 | case 1: { /* data */ executed 16 times by 1 test: case 1: Executed by:
| 16 | ||||||||||||||||||
275 | DbPage *pDbPage = 0; | - | ||||||||||||||||||
276 | rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); | - | ||||||||||||||||||
277 | if( rc==SQLITE_OK ){
| 0-16 | ||||||||||||||||||
278 | sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage, | - | ||||||||||||||||||
279 | SQLITE_TRANSIENT); | - | ||||||||||||||||||
280 | } executed 16 times by 1 test: end of block Executed by:
| 16 | ||||||||||||||||||
281 | sqlite3PagerUnref(pDbPage); | - | ||||||||||||||||||
282 | break; executed 16 times by 1 test: break; Executed by:
| 16 | ||||||||||||||||||
283 | } | - | ||||||||||||||||||
284 | default: { /* schema */ executed 10 times by 1 test: default: Executed by:
| 10 | ||||||||||||||||||
285 | sqlite3 *db = sqlite3_context_db_handle(ctx); | - | ||||||||||||||||||
286 | sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC); | - | ||||||||||||||||||
287 | break; executed 10 times by 1 test: break; Executed by:
| 10 | ||||||||||||||||||
288 | } | - | ||||||||||||||||||
289 | } | - | ||||||||||||||||||
290 | return SQLITE_OK; executed 48 times by 1 test: return 0; Executed by:
| 48 | ||||||||||||||||||
291 | } | - | ||||||||||||||||||
292 | - | |||||||||||||||||||
293 | static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ | - | ||||||||||||||||||
294 | DbpageCursor *pCsr = (DbpageCursor *)pCursor; | - | ||||||||||||||||||
295 | *pRowid = pCsr->pgno; | - | ||||||||||||||||||
296 | return SQLITE_OK; executed 16 times by 1 test: return 0; Executed by:
| 16 | ||||||||||||||||||
297 | } | - | ||||||||||||||||||
298 | - | |||||||||||||||||||
299 | static int dbpageUpdate( | - | ||||||||||||||||||
300 | sqlite3_vtab *pVtab, | - | ||||||||||||||||||
301 | int argc, | - | ||||||||||||||||||
302 | sqlite3_value **argv, | - | ||||||||||||||||||
303 | sqlite_int64 *pRowid | - | ||||||||||||||||||
304 | ){ | - | ||||||||||||||||||
305 | DbpageTable *pTab = (DbpageTable *)pVtab; | - | ||||||||||||||||||
306 | Pgno pgno; | - | ||||||||||||||||||
307 | DbPage *pDbPage = 0; | - | ||||||||||||||||||
308 | int rc = SQLITE_OK; | - | ||||||||||||||||||
309 | char *zErr = 0; | - | ||||||||||||||||||
310 | const char *zSchema; | - | ||||||||||||||||||
311 | int iDb; | - | ||||||||||||||||||
312 | Btree *pBt; | - | ||||||||||||||||||
313 | Pager *pPager; | - | ||||||||||||||||||
314 | int szPage; | - | ||||||||||||||||||
315 | - | |||||||||||||||||||
316 | if( argc==1 ){
| 0-8 | ||||||||||||||||||
317 | zErr = "cannot delete"; | - | ||||||||||||||||||
318 | goto update_fail; never executed: goto update_fail; | 0 | ||||||||||||||||||
319 | } | - | ||||||||||||||||||
320 | pgno = sqlite3_value_int(argv[0]); | - | ||||||||||||||||||
321 | if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
| 0-8 | ||||||||||||||||||
322 | zErr = "cannot insert"; | - | ||||||||||||||||||
323 | goto update_fail; never executed: goto update_fail; | 0 | ||||||||||||||||||
324 | } | - | ||||||||||||||||||
325 | zSchema = (const char*)sqlite3_value_text(argv[4]); | - | ||||||||||||||||||
326 | iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
| 0-8 | ||||||||||||||||||
327 | if( iDb<0 ){
| 0-8 | ||||||||||||||||||
328 | zErr = "no such schema"; | - | ||||||||||||||||||
329 | goto update_fail; never executed: goto update_fail; | 0 | ||||||||||||||||||
330 | } | - | ||||||||||||||||||
331 | pBt = pTab->db->aDb[iDb].pBt; | - | ||||||||||||||||||
332 | if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){
| 0-8 | ||||||||||||||||||
333 | zErr = "bad page number"; | - | ||||||||||||||||||
334 | goto update_fail; never executed: goto update_fail; | 0 | ||||||||||||||||||
335 | } | - | ||||||||||||||||||
336 | szPage = sqlite3BtreeGetPageSize(pBt); | - | ||||||||||||||||||
337 | if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
| 0-8 | ||||||||||||||||||
338 | || sqlite3_value_bytes(argv[3])!=szPage
| 0-8 | ||||||||||||||||||
339 | ){ | - | ||||||||||||||||||
340 | zErr = "bad page value"; | - | ||||||||||||||||||
341 | goto update_fail; never executed: goto update_fail; | 0 | ||||||||||||||||||
342 | } | - | ||||||||||||||||||
343 | pPager = sqlite3BtreePager(pBt); | - | ||||||||||||||||||
344 | rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); | - | ||||||||||||||||||
345 | if( rc==SQLITE_OK ){
| 0-8 | ||||||||||||||||||
346 | rc = sqlite3PagerWrite(pDbPage); | - | ||||||||||||||||||
347 | if( rc==SQLITE_OK ){
| 0-8 | ||||||||||||||||||
348 | memcpy(sqlite3PagerGetData(pDbPage), | - | ||||||||||||||||||
349 | sqlite3_value_blob(argv[3]), | - | ||||||||||||||||||
350 | szPage); | - | ||||||||||||||||||
351 | } executed 8 times by 1 test: end of block Executed by:
| 8 | ||||||||||||||||||
352 | } executed 8 times by 1 test: end of block Executed by:
| 8 | ||||||||||||||||||
353 | sqlite3PagerUnref(pDbPage); | - | ||||||||||||||||||
354 | return rc; executed 8 times by 1 test: return rc; Executed by:
| 8 | ||||||||||||||||||
355 | - | |||||||||||||||||||
356 | update_fail: | - | ||||||||||||||||||
357 | sqlite3_free(pVtab->zErrMsg); | - | ||||||||||||||||||
358 | pVtab->zErrMsg = sqlite3_mprintf("%s", zErr); | - | ||||||||||||||||||
359 | return SQLITE_ERROR; never executed: return 1; | 0 | ||||||||||||||||||
360 | } | - | ||||||||||||||||||
361 | - | |||||||||||||||||||
362 | /* Since we do not know in advance which database files will be | - | ||||||||||||||||||
363 | ** written by the sqlite_dbpage virtual table, start a write transaction | - | ||||||||||||||||||
364 | ** on them all. | - | ||||||||||||||||||
365 | */ | - | ||||||||||||||||||
366 | static int dbpageBegin(sqlite3_vtab *pVtab){ | - | ||||||||||||||||||
367 | DbpageTable *pTab = (DbpageTable *)pVtab; | - | ||||||||||||||||||
368 | sqlite3 *db = pTab->db; | - | ||||||||||||||||||
369 | int i; | - | ||||||||||||||||||
370 | for(i=0; i<db->nDb; i++){
| 8-20 | ||||||||||||||||||
371 | Btree *pBt = db->aDb[i].pBt; | - | ||||||||||||||||||
372 | if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0); executed 19 times by 1 test: sqlite3BtreeBeginTrans(pBt, 1, 0); Executed by:
| 1-19 | ||||||||||||||||||
373 | } executed 20 times by 1 test: end of block Executed by:
| 20 | ||||||||||||||||||
374 | return SQLITE_OK; executed 8 times by 1 test: return 0; Executed by:
| 8 | ||||||||||||||||||
375 | } | - | ||||||||||||||||||
376 | - | |||||||||||||||||||
377 | - | |||||||||||||||||||
378 | /* | - | ||||||||||||||||||
379 | ** Invoke this routine to register the "dbpage" virtual table module | - | ||||||||||||||||||
380 | */ | - | ||||||||||||||||||
381 | int sqlite3DbpageRegister(sqlite3 *db){ | - | ||||||||||||||||||
382 | static sqlite3_module dbpage_module = { | - | ||||||||||||||||||
383 | 0, /* iVersion */ | - | ||||||||||||||||||
384 | dbpageConnect, /* xCreate */ | - | ||||||||||||||||||
385 | dbpageConnect, /* xConnect */ | - | ||||||||||||||||||
386 | dbpageBestIndex, /* xBestIndex */ | - | ||||||||||||||||||
387 | dbpageDisconnect, /* xDisconnect */ | - | ||||||||||||||||||
388 | dbpageDisconnect, /* xDestroy */ | - | ||||||||||||||||||
389 | dbpageOpen, /* xOpen - open a cursor */ | - | ||||||||||||||||||
390 | dbpageClose, /* xClose - close a cursor */ | - | ||||||||||||||||||
391 | dbpageFilter, /* xFilter - configure scan constraints */ | - | ||||||||||||||||||
392 | dbpageNext, /* xNext - advance a cursor */ | - | ||||||||||||||||||
393 | dbpageEof, /* xEof - check for end of scan */ | - | ||||||||||||||||||
394 | dbpageColumn, /* xColumn - read data */ | - | ||||||||||||||||||
395 | dbpageRowid, /* xRowid - read data */ | - | ||||||||||||||||||
396 | dbpageUpdate, /* xUpdate */ | - | ||||||||||||||||||
397 | dbpageBegin, /* xBegin */ | - | ||||||||||||||||||
398 | 0, /* xSync */ | - | ||||||||||||||||||
399 | 0, /* xCommit */ | - | ||||||||||||||||||
400 | 0, /* xRollback */ | - | ||||||||||||||||||
401 | 0, /* xFindMethod */ | - | ||||||||||||||||||
402 | 0, /* xRename */ | - | ||||||||||||||||||
403 | 0, /* xSavepoint */ | - | ||||||||||||||||||
404 | 0, /* xRelease */ | - | ||||||||||||||||||
405 | 0, /* xRollbackTo */ | - | ||||||||||||||||||
406 | }; | - | ||||||||||||||||||
407 | return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); executed 31552 times by 438 tests: return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); Executed by:
| 31552 | ||||||||||||||||||
408 | } | - | ||||||||||||||||||
409 | #elif defined(SQLITE_ENABLE_DBPAGE_VTAB) | - | ||||||||||||||||||
410 | int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; } | - | ||||||||||||||||||
411 | #endif /* SQLITE_ENABLE_DBSTAT_VTAB */ | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |