From 4f49b16079b27d7ce633619e4cddfdf2bffbc952 Mon Sep 17 00:00:00 2001 From: cashmere Date: Fri, 4 Sep 2026 09:05:24 +0200 Subject: initial commit --- src/foci.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 src/foci.c (limited to 'src/foci.c') diff --git a/src/foci.c b/src/foci.c new file mode 100644 index 0000000..20fea47 --- /dev/null +++ b/src/foci.c @@ -0,0 +1,278 @@ +/* +** Copyright (c) 2014 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the Simplified BSD License (also +** known as the "2-Clause License" or "FreeBSD License".) + +** This program is distributed in the hope that it will be useful, +** but without any warranty; without even the implied warranty of +** merchantability or fitness for a particular purpose. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +******************************************************************************* +** +** This routine implements eponymous virtual table for SQLite that gives +** all of the files associated with a single check-in. The table works +** as a table-valued function. +** +** The source code filename "foci" is short for "Files of Check-in". +** +** Usage example: +** +** SELECT * FROM files_of_checkin('trunk'); +** +** The "schema" for the temp.foci table is: +** +** CREATE TABLE files_of_checkin( +** checkinID INTEGER, -- RID for the check-in manifest +** filename TEXT, -- Name of a file +** uuid TEXT, -- hash of the file +** previousName TEXT, -- Name of the file in previous check-in +** perm TEXT, -- Permissions on the file +** symname TEXT HIDDEN -- Symbolic name of the check-in. +** ); +** +** The hidden symname column is (optionally) used as a query parameter to +** identify the particular check-in to parse. The checkinID parameter +** (such is a unique numeric RID rather than symbolic name) can also be used +** to identify the check-in. Example: +** +** SELECT * FROM files_of_checkin +** WHERE checkinID=symbolic_name_to_rid('trunk'); +** +*/ +#include "config.h" +#include "foci.h" +#include + +/* +** The schema for the virtual table: +*/ +static const char zFociSchema[] = +@ CREATE TABLE files_of_checkin( +@ checkinID INTEGER, -- RID for the check-in manifest +@ filename TEXT, -- Name of a file +@ uuid TEXT, -- hash of the file +@ previousName TEXT, -- Name of the file in previous check-in +@ perm TEXT, -- Permissions on the file +@ symname TEXT HIDDEN -- Symbolic name of the check-in +@ ); +; + +#define FOCI_CHECKINID 0 +#define FOCI_FILENAME 1 +#define FOCI_UUID 2 +#define FOCI_PREVNAME 3 +#define FOCI_PERM 4 +#define FOCI_SYMNAME 5 + +#if INTERFACE +/* +** The subclasses of sqlite3_vtab and sqlite3_vtab_cursor tables +** that implement the files_of_checkin virtual table. +*/ +struct FociTable { + sqlite3_vtab base; /* Base class - must be first */ +}; +struct FociCursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + Manifest *pMan; /* Current manifest */ + ManifestFile *pFile; /* Current file */ + int iFile; /* File index */ +}; +#endif /* INTERFACE */ + + +/* +** Connect to or create a foci virtual table. +*/ +static int fociConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + FociTable *pTab; + + pTab = (FociTable *)sqlite3_malloc(sizeof(FociTable)); + memset(pTab, 0, sizeof(FociTable)); + sqlite3_declare_vtab(db, zFociSchema); + *ppVtab = &pTab->base; + return SQLITE_OK; +} + +/* +** Disconnect from or destroy a focivfs virtual table. +*/ +static int fociDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** Available scan methods: +** +** (0) A full scan. Visit every manifest in the repo. (Slow) +** (1) checkinID=?. visit only the single manifest specified. +** (2) symName=? visit only the single manifest specified. +*/ +static int fociBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + int i; + pIdxInfo->estimatedCost = 1000000000.0; + for(i=0; inConstraint; i++){ + if( !pIdxInfo->aConstraint[i].usable ) continue; + if( pIdxInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ + && (pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID + || pIdxInfo->aConstraint[i].iColumn==FOCI_SYMNAME) + ){ + if( pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID ){ + pIdxInfo->idxNum = 1; + }else{ + pIdxInfo->idxNum = 2; + } + pIdxInfo->estimatedCost = 1.0; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + break; + } + } + return SQLITE_OK; +} + +/* +** Open a new focivfs cursor. +*/ +static int fociOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + FociCursor *pCsr; + pCsr = (FociCursor *)sqlite3_malloc(sizeof(FociCursor)); + memset(pCsr, 0, sizeof(FociCursor)); + pCsr->base.pVtab = pVTab; + *ppCursor = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Close a focivfs cursor. +*/ +static int fociClose(sqlite3_vtab_cursor *pCursor){ + FociCursor *pCsr = (FociCursor *)pCursor; + manifest_destroy(pCsr->pMan); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Move a focivfs cursor to the next entry in the file. +*/ +static int fociNext(sqlite3_vtab_cursor *pCursor){ + FociCursor *pCsr = (FociCursor *)pCursor; + pCsr->pFile = manifest_file_next(pCsr->pMan, 0); + pCsr->iFile++; + return SQLITE_OK; +} + +static int fociEof(sqlite3_vtab_cursor *pCursor){ + FociCursor *pCsr = (FociCursor *)pCursor; + return pCsr->pFile==0; +} + +static int fociFilter( + sqlite3_vtab_cursor *pCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + FociCursor *pCur = (FociCursor *)pCursor; + manifest_destroy(pCur->pMan); + if( idxNum ){ + int rid; + if( idxNum==1 ){ + rid = sqlite3_value_int(argv[0]); + }else{ + rid = symbolic_name_to_rid((const char*)sqlite3_value_text(argv[0]),"ci"); + } + pCur->pMan = manifest_get(rid, CFTYPE_MANIFEST, 0); + if( pCur->pMan ){ + manifest_file_rewind(pCur->pMan); + pCur->pFile = manifest_file_next(pCur->pMan, 0); + } + }else{ + pCur->pMan = 0; + } + pCur->iFile = 0; + return SQLITE_OK; +} + +static int fociColumn( + sqlite3_vtab_cursor *pCursor, + sqlite3_context *ctx, + int i +){ + FociCursor *pCsr = (FociCursor *)pCursor; + switch( i ){ + case FOCI_CHECKINID: + sqlite3_result_int(ctx, pCsr->pMan->rid); + break; + case FOCI_FILENAME: + sqlite3_result_text(ctx, pCsr->pFile->zName, -1, + SQLITE_TRANSIENT); + break; + case FOCI_UUID: + sqlite3_result_text(ctx, pCsr->pFile->zUuid, -1, + SQLITE_TRANSIENT); + break; + case FOCI_PREVNAME: + sqlite3_result_text(ctx, pCsr->pFile->zPrior, -1, + SQLITE_TRANSIENT); + break; + case FOCI_PERM: + sqlite3_result_text(ctx, pCsr->pFile->zPerm, -1, + SQLITE_TRANSIENT); + break; + case FOCI_SYMNAME: + break; + } + return SQLITE_OK; +} + +static int fociRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ + FociCursor *pCsr = (FociCursor *)pCursor; + *pRowid = pCsr->iFile; + return SQLITE_OK; +} + +int foci_register(sqlite3 *db){ + static sqlite3_module foci_module = { + 0, /* iVersion */ + fociConnect, /* xCreate */ + fociConnect, /* xConnect */ + fociBestIndex, /* xBestIndex */ + fociDisconnect, /* xDisconnect */ + fociDisconnect, /* xDestroy */ + fociOpen, /* xOpen - open a cursor */ + fociClose, /* xClose - close a cursor */ + fociFilter, /* xFilter - configure scan constraints */ + fociNext, /* xNext - advance a cursor */ + fociEof, /* xEof - check for end of scan */ + fociColumn, /* xColumn - read data */ + fociRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindFunction */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0, /* xShadowName */ + 0 /* xIntegrity */ + }; + sqlite3_create_module(db, "files_of_checkin", &foci_module, 0); + return SQLITE_OK; +} -- cgit v1.3.1