Fossil SCM

fossil-scm / src / foci.c
Blame History Raw 279 lines
1
/*
2
** Copyright (c) 2014 D. Richard Hipp
3
**
4
** This program is free software; you can redistribute it and/or
5
** modify it under the terms of the Simplified BSD License (also
6
** known as the "2-Clause License" or "FreeBSD License".)
7
8
** This program is distributed in the hope that it will be useful,
9
** but without any warranty; without even the implied warranty of
10
** merchantability or fitness for a particular purpose.
11
**
12
** Author contact information:
13
** [email protected]
14
** http://www.hwaci.com/drh/
15
**
16
*******************************************************************************
17
**
18
** This routine implements eponymous virtual table for SQLite that gives
19
** all of the files associated with a single check-in. The table works
20
** as a table-valued function.
21
**
22
** The source code filename "foci" is short for "Files of Check-in".
23
**
24
** Usage example:
25
**
26
** SELECT * FROM files_of_checkin('trunk');
27
**
28
** The "schema" for the temp.foci table is:
29
**
30
** CREATE TABLE files_of_checkin(
31
** checkinID INTEGER, -- RID for the check-in manifest
32
** filename TEXT, -- Name of a file
33
** uuid TEXT, -- hash of the file
34
** previousName TEXT, -- Name of the file in previous check-in
35
** perm TEXT, -- Permissions on the file
36
** symname TEXT HIDDEN -- Symbolic name of the check-in.
37
** );
38
**
39
** The hidden symname column is (optionally) used as a query parameter to
40
** identify the particular check-in to parse. The checkinID parameter
41
** (such is a unique numeric RID rather than symbolic name) can also be used
42
** to identify the check-in. Example:
43
**
44
** SELECT * FROM files_of_checkin
45
** WHERE checkinID=symbolic_name_to_rid('trunk');
46
**
47
*/
48
#include "config.h"
49
#include "foci.h"
50
#include <assert.h>
51
52
/*
53
** The schema for the virtual table:
54
*/
55
static const char zFociSchema[] =
56
@ CREATE TABLE files_of_checkin(
57
@ checkinID INTEGER, -- RID for the check-in manifest
58
@ filename TEXT, -- Name of a file
59
@ uuid TEXT, -- hash of the file
60
@ previousName TEXT, -- Name of the file in previous check-in
61
@ perm TEXT, -- Permissions on the file
62
@ symname TEXT HIDDEN -- Symbolic name of the check-in
63
@ );
64
;
65
66
#define FOCI_CHECKINID 0
67
#define FOCI_FILENAME 1
68
#define FOCI_UUID 2
69
#define FOCI_PREVNAME 3
70
#define FOCI_PERM 4
71
#define FOCI_SYMNAME 5
72
73
#if INTERFACE
74
/*
75
** The subclasses of sqlite3_vtab and sqlite3_vtab_cursor tables
76
** that implement the files_of_checkin virtual table.
77
*/
78
struct FociTable {
79
sqlite3_vtab base; /* Base class - must be first */
80
};
81
struct FociCursor {
82
sqlite3_vtab_cursor base; /* Base class - must be first */
83
Manifest *pMan; /* Current manifest */
84
ManifestFile *pFile; /* Current file */
85
int iFile; /* File index */
86
};
87
#endif /* INTERFACE */
88
89
90
/*
91
** Connect to or create a foci virtual table.
92
*/
93
static int fociConnect(
94
sqlite3 *db,
95
void *pAux,
96
int argc, const char *const*argv,
97
sqlite3_vtab **ppVtab,
98
char **pzErr
99
){
100
FociTable *pTab;
101
102
pTab = (FociTable *)sqlite3_malloc(sizeof(FociTable));
103
memset(pTab, 0, sizeof(FociTable));
104
sqlite3_declare_vtab(db, zFociSchema);
105
*ppVtab = &pTab->base;
106
return SQLITE_OK;
107
}
108
109
/*
110
** Disconnect from or destroy a focivfs virtual table.
111
*/
112
static int fociDisconnect(sqlite3_vtab *pVtab){
113
sqlite3_free(pVtab);
114
return SQLITE_OK;
115
}
116
117
/*
118
** Available scan methods:
119
**
120
** (0) A full scan. Visit every manifest in the repo. (Slow)
121
** (1) checkinID=?. visit only the single manifest specified.
122
** (2) symName=? visit only the single manifest specified.
123
*/
124
static int fociBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
125
int i;
126
pIdxInfo->estimatedCost = 1000000000.0;
127
for(i=0; i<pIdxInfo->nConstraint; i++){
128
if( !pIdxInfo->aConstraint[i].usable ) continue;
129
if( pIdxInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
130
&& (pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID
131
|| pIdxInfo->aConstraint[i].iColumn==FOCI_SYMNAME)
132
){
133
if( pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID ){
134
pIdxInfo->idxNum = 1;
135
}else{
136
pIdxInfo->idxNum = 2;
137
}
138
pIdxInfo->estimatedCost = 1.0;
139
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
140
pIdxInfo->aConstraintUsage[i].omit = 1;
141
break;
142
}
143
}
144
return SQLITE_OK;
145
}
146
147
/*
148
** Open a new focivfs cursor.
149
*/
150
static int fociOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
151
FociCursor *pCsr;
152
pCsr = (FociCursor *)sqlite3_malloc(sizeof(FociCursor));
153
memset(pCsr, 0, sizeof(FociCursor));
154
pCsr->base.pVtab = pVTab;
155
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
156
return SQLITE_OK;
157
}
158
159
/*
160
** Close a focivfs cursor.
161
*/
162
static int fociClose(sqlite3_vtab_cursor *pCursor){
163
FociCursor *pCsr = (FociCursor *)pCursor;
164
manifest_destroy(pCsr->pMan);
165
sqlite3_free(pCsr);
166
return SQLITE_OK;
167
}
168
169
/*
170
** Move a focivfs cursor to the next entry in the file.
171
*/
172
static int fociNext(sqlite3_vtab_cursor *pCursor){
173
FociCursor *pCsr = (FociCursor *)pCursor;
174
pCsr->pFile = manifest_file_next(pCsr->pMan, 0);
175
pCsr->iFile++;
176
return SQLITE_OK;
177
}
178
179
static int fociEof(sqlite3_vtab_cursor *pCursor){
180
FociCursor *pCsr = (FociCursor *)pCursor;
181
return pCsr->pFile==0;
182
}
183
184
static int fociFilter(
185
sqlite3_vtab_cursor *pCursor,
186
int idxNum, const char *idxStr,
187
int argc, sqlite3_value **argv
188
){
189
FociCursor *pCur = (FociCursor *)pCursor;
190
manifest_destroy(pCur->pMan);
191
if( idxNum ){
192
int rid;
193
if( idxNum==1 ){
194
rid = sqlite3_value_int(argv[0]);
195
}else{
196
rid = symbolic_name_to_rid((const char*)sqlite3_value_text(argv[0]),"ci");
197
}
198
pCur->pMan = manifest_get(rid, CFTYPE_MANIFEST, 0);
199
if( pCur->pMan ){
200
manifest_file_rewind(pCur->pMan);
201
pCur->pFile = manifest_file_next(pCur->pMan, 0);
202
}
203
}else{
204
pCur->pMan = 0;
205
}
206
pCur->iFile = 0;
207
return SQLITE_OK;
208
}
209
210
static int fociColumn(
211
sqlite3_vtab_cursor *pCursor,
212
sqlite3_context *ctx,
213
int i
214
){
215
FociCursor *pCsr = (FociCursor *)pCursor;
216
switch( i ){
217
case FOCI_CHECKINID:
218
sqlite3_result_int(ctx, pCsr->pMan->rid);
219
break;
220
case FOCI_FILENAME:
221
sqlite3_result_text(ctx, pCsr->pFile->zName, -1,
222
SQLITE_TRANSIENT);
223
break;
224
case FOCI_UUID:
225
sqlite3_result_text(ctx, pCsr->pFile->zUuid, -1,
226
SQLITE_TRANSIENT);
227
break;
228
case FOCI_PREVNAME:
229
sqlite3_result_text(ctx, pCsr->pFile->zPrior, -1,
230
SQLITE_TRANSIENT);
231
break;
232
case FOCI_PERM:
233
sqlite3_result_text(ctx, pCsr->pFile->zPerm, -1,
234
SQLITE_TRANSIENT);
235
break;
236
case FOCI_SYMNAME:
237
break;
238
}
239
return SQLITE_OK;
240
}
241
242
static int fociRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
243
FociCursor *pCsr = (FociCursor *)pCursor;
244
*pRowid = pCsr->iFile;
245
return SQLITE_OK;
246
}
247
248
int foci_register(sqlite3 *db){
249
static sqlite3_module foci_module = {
250
0, /* iVersion */
251
fociConnect, /* xCreate */
252
fociConnect, /* xConnect */
253
fociBestIndex, /* xBestIndex */
254
fociDisconnect, /* xDisconnect */
255
fociDisconnect, /* xDestroy */
256
fociOpen, /* xOpen - open a cursor */
257
fociClose, /* xClose - close a cursor */
258
fociFilter, /* xFilter - configure scan constraints */
259
fociNext, /* xNext - advance a cursor */
260
fociEof, /* xEof - check for end of scan */
261
fociColumn, /* xColumn - read data */
262
fociRowid, /* xRowid - read data */
263
0, /* xUpdate */
264
0, /* xBegin */
265
0, /* xSync */
266
0, /* xCommit */
267
0, /* xRollback */
268
0, /* xFindFunction */
269
0, /* xRename */
270
0, /* xSavepoint */
271
0, /* xRelease */
272
0, /* xRollbackTo */
273
0, /* xShadowName */
274
0 /* xIntegrity */
275
};
276
sqlite3_create_module(db, "files_of_checkin", &foci_module, 0);
277
return SQLITE_OK;
278
}
279

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button