mirror of
https://github.com/tursodatabase/libsql.git
synced 2025-06-03 09:35:35 +00:00
.cargo
.config
.github
bindings
bottomless
bottomless-cli
docker-compose
docs
libsql
libsql-ffi
libsql-hrana
libsql-replication
libsql-server
libsql-shell
libsql-sqlite3
art
autoconf
benchmark
contrib
crates
doc
ext
mptest
src
test
testdir
tool
win
GetFile.cs
GetTclKit.bat
Replace.cs
build-all-msvc.bat
build-shell.sh
cg_anno.tcl
checkSpacing.c
cktclsh.sh
custom.txt
dbhash.c
dbtotxt.c
dbtotxt.md
enlargedb.c
extract-sqlite3h.tcl
extract.c
fast_vacuum.c
fragck.tcl
fuzzershell.c
generate-artifacts.sh
genfkey.README
genfkey.test
getlock.c
index_usage.c
kvtest-speed.sh
lemon.c
lempar.c
libvers.c
loadfts.c
logest.c
max-limits.c
merge-test.tcl
mkautoconfamal.sh
mkccode.tcl
mkctimec.tcl
mkkeywordhash.c
mkmsvcmin.tcl
mkopcodec.tcl
mkopcodeh.tcl
mkopts.tcl
mkpragmatab.tcl
mkshellc.tcl
mksourceid.c
mkspeedsql.tcl
mksqlite3c-noext.tcl
mksqlite3c.tcl
mksqlite3h.tcl
mksqlite3internalh.tcl
mktoolzip.tcl
mkvsix.tcl
offsets.c
omittest-msvc.tcl
omittest.tcl
opcodesum.tcl
pagesig.c
pre-release.sh
replace.tcl
restore_jrnl.tcl
rollback-test.c
run-speed-test.sh
showdb.c
showjournal.c
showlocks.c
showshm.c
showstat4.c
showwal
showwal.c
soak1.tcl
spaceanal.tcl
speed-check.sh
speedtest.tcl
speedtest16.c
speedtest2.tcl
speedtest8.c
speedtest8inst1.c
spellsift.tcl
split-sqlite3c.tcl
sqldiff.c
sqlite3_analyzer.c.in
sqltclsh.c.in
sqltclsh.tcl
src-verify.c
srcck1.c
srctree-check.tcl
stack_usage.tcl
stripccomments.c
symbols-mingw.sh
symbols.sh
varint.c
vdbe-compress.tcl
vdbe_profile.tcl
vectoridx_graphviz.py
version-info.c
warnings-clang.sh
warnings.sh
vsixtest
.gitignore
Dockerfile-wasm-udf
LIBSQL_VERSION
LICENSE.md
Makefile.in
Makefile.linux-gcc
Makefile.msc
README-SQLite.md
VERSION
aclocal.m4
config.guess
config.sub
configure
configure.ac
install-sh
libsql.pc.in
ltmain.sh
magic.txt
main.mk
manifest
manifest.uuid
spec.template
sqlite.pc.in
sqlite3.1
sqlite3.pc.in
sqlite_cfg.h.in
libsql-sys
scripts
tools
vendored
xtask
.dockerignore
.env
.gitignore
.gitmodules
.markdownlint.yaml
CODE_OF_CONDUCT.md
CONTRIBUTING.md
Cargo.lock
Cargo.toml
Dockerfile
Dockerfile.dev
Dockerfile.musl
LICENSE.md
README-libsql.md
README.md
docker-entrypoint.sh
docker-wrapper.sh
fly.toml
rust-toolchain.toml
243 lines
6.9 KiB
C
243 lines
6.9 KiB
C
/*
|
|
** 2014-07-28
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
**
|
|
** This file implements a utility program that will load many disk
|
|
** files (all files under a given directory) into a FTS table. This is
|
|
** used for performance testing of FTS3, FTS4, and FTS5.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <dirent.h>
|
|
#include "sqlite3.h"
|
|
|
|
/*
|
|
** Implementation of the "readtext(X)" SQL function. The entire content
|
|
** of the file named X is read and returned as a TEXT value. It is assumed
|
|
** the file contains UTF-8 text. NULL is returned if the file does not
|
|
** exist or is unreadable.
|
|
*/
|
|
static void readfileFunc(
|
|
sqlite3_context *context,
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
const char *zName;
|
|
FILE *in;
|
|
long nIn;
|
|
void *pBuf;
|
|
|
|
zName = (const char*)sqlite3_value_text(argv[0]);
|
|
if( zName==0 ) return;
|
|
in = fopen(zName, "rb");
|
|
if( in==0 ) return;
|
|
fseek(in, 0, SEEK_END);
|
|
nIn = ftell(in);
|
|
rewind(in);
|
|
pBuf = sqlite3_malloc( nIn );
|
|
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
|
|
sqlite3_result_text(context, pBuf, nIn, sqlite3_free);
|
|
}else{
|
|
sqlite3_free(pBuf);
|
|
}
|
|
fclose(in);
|
|
}
|
|
|
|
/*
|
|
** Print usage text for this program and exit.
|
|
*/
|
|
static void showHelp(const char *zArgv0){
|
|
printf("\n"
|
|
"Usage: %s SWITCHES... DB\n"
|
|
"\n"
|
|
" This program opens the database named on the command line and attempts to\n"
|
|
" create an FTS table named \"fts\" with a single column. If successful, it\n"
|
|
" recursively traverses the directory named by the -dir option and inserts\n"
|
|
" the contents of each file into the fts table. All files are assumed to\n"
|
|
" contain UTF-8 text.\n"
|
|
"\n"
|
|
"Switches are:\n"
|
|
" -fts [345] FTS version to use (default=5)\n"
|
|
" -idx [01] Create a mapping from filename to rowid (default=0)\n"
|
|
" -dir <path> Root of directory tree to load data from (default=.)\n"
|
|
" -trans <integer> Number of inserts per transaction (default=1)\n"
|
|
, zArgv0
|
|
);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
** Exit with a message based on the argument and the current value of errno.
|
|
*/
|
|
static void error_out(const char *zText){
|
|
fprintf(stderr, "%s: %s\n", zText, strerror(errno));
|
|
exit(-1);
|
|
}
|
|
|
|
/*
|
|
** Exit with a message based on the first argument and the error message
|
|
** currently stored in database handle db.
|
|
*/
|
|
static void sqlite_error_out(const char *zText, sqlite3 *db){
|
|
fprintf(stderr, "%s: %s\n", zText, sqlite3_errmsg(db));
|
|
exit(-1);
|
|
}
|
|
|
|
/*
|
|
** Context object for visit_file().
|
|
*/
|
|
typedef struct VisitContext VisitContext;
|
|
struct VisitContext {
|
|
int nRowPerTrans;
|
|
sqlite3 *db; /* Database handle */
|
|
sqlite3_stmt *pInsert; /* INSERT INTO fts VALUES(readtext(:1)) */
|
|
};
|
|
|
|
/*
|
|
** Callback used with traverse(). The first argument points to an object
|
|
** of type VisitContext. This function inserts the contents of the text
|
|
** file zPath into the FTS table.
|
|
*/
|
|
void visit_file(void *pCtx, const char *zPath){
|
|
int rc;
|
|
VisitContext *p = (VisitContext*)pCtx;
|
|
/* printf("%s\n", zPath); */
|
|
sqlite3_bind_text(p->pInsert, 1, zPath, -1, SQLITE_STATIC);
|
|
sqlite3_step(p->pInsert);
|
|
rc = sqlite3_reset(p->pInsert);
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite_error_out("insert", p->db);
|
|
}else if( p->nRowPerTrans>0
|
|
&& (sqlite3_last_insert_rowid(p->db) % p->nRowPerTrans)==0
|
|
){
|
|
sqlite3_exec(p->db, "COMMIT ; BEGIN", 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Recursively traverse directory zDir. For each file that is not a
|
|
** directory, invoke the supplied callback with its path.
|
|
*/
|
|
static void traverse(
|
|
const char *zDir, /* Directory to traverse */
|
|
void *pCtx, /* First argument passed to callback */
|
|
void (*xCallback)(void*, const char *zPath)
|
|
){
|
|
DIR *d;
|
|
struct dirent *e;
|
|
|
|
d = opendir(zDir);
|
|
if( d==0 ) error_out("opendir()");
|
|
|
|
for(e=readdir(d); e; e=readdir(d)){
|
|
if( strcmp(e->d_name, ".")==0 || strcmp(e->d_name, "..")==0 ) continue;
|
|
char *zPath = sqlite3_mprintf("%s/%s", zDir, e->d_name);
|
|
if (e->d_type & DT_DIR) {
|
|
traverse(zPath, pCtx, xCallback);
|
|
}else{
|
|
xCallback(pCtx, zPath);
|
|
}
|
|
sqlite3_free(zPath);
|
|
}
|
|
|
|
closedir(d);
|
|
}
|
|
|
|
int main(int argc, char **argv){
|
|
int iFts = 5; /* Value of -fts option */
|
|
int bMap = 0; /* True to create mapping table */
|
|
const char *zDir = "."; /* Directory to scan */
|
|
int i;
|
|
int rc;
|
|
int nRowPerTrans = 0;
|
|
sqlite3 *db;
|
|
char *zSql;
|
|
VisitContext sCtx;
|
|
|
|
int nCmd = 0;
|
|
char **aCmd = 0;
|
|
|
|
if( argc % 2 ) showHelp(argv[0]);
|
|
|
|
for(i=1; i<(argc-1); i+=2){
|
|
char *zOpt = argv[i];
|
|
char *zArg = argv[i+1];
|
|
if( strcmp(zOpt, "-fts")==0 ){
|
|
iFts = atoi(zArg);
|
|
if( iFts!=3 && iFts!=4 && iFts!= 5) showHelp(argv[0]);
|
|
}
|
|
else if( strcmp(zOpt, "-trans")==0 ){
|
|
nRowPerTrans = atoi(zArg);
|
|
}
|
|
else if( strcmp(zOpt, "-idx")==0 ){
|
|
bMap = atoi(zArg);
|
|
if( bMap!=0 && bMap!=1 ) showHelp(argv[0]);
|
|
}
|
|
else if( strcmp(zOpt, "-dir")==0 ){
|
|
zDir = zArg;
|
|
}
|
|
else if( strcmp(zOpt, "-special")==0 ){
|
|
nCmd++;
|
|
aCmd = sqlite3_realloc(aCmd, sizeof(char*) * nCmd);
|
|
aCmd[nCmd-1] = zArg;
|
|
}
|
|
else{
|
|
showHelp(argv[0]);
|
|
}
|
|
}
|
|
|
|
/* Open the database file */
|
|
rc = sqlite3_open(argv[argc-1], &db);
|
|
if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_open()", db);
|
|
|
|
rc = sqlite3_create_function(db, "readtext", 1, SQLITE_UTF8, 0,
|
|
readfileFunc, 0, 0);
|
|
if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_create_function()", db);
|
|
|
|
/* Create the FTS table */
|
|
zSql = sqlite3_mprintf("CREATE VIRTUAL TABLE fts USING fts%d(content)", iFts);
|
|
rc = sqlite3_exec(db, zSql, 0, 0, 0);
|
|
if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_exec(1)", db);
|
|
sqlite3_free(zSql);
|
|
|
|
for(i=0; i<nCmd; i++){
|
|
zSql = sqlite3_mprintf("INSERT INTO fts(fts) VALUES(%Q)", aCmd[i]);
|
|
rc = sqlite3_exec(db, zSql, 0, 0, 0);
|
|
if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_exec(1)", db);
|
|
sqlite3_free(zSql);
|
|
}
|
|
|
|
/* Compile the INSERT statement to write data to the FTS table. */
|
|
memset(&sCtx, 0, sizeof(VisitContext));
|
|
sCtx.db = db;
|
|
sCtx.nRowPerTrans = nRowPerTrans;
|
|
rc = sqlite3_prepare_v2(db,
|
|
"INSERT INTO fts VALUES(readtext(?))", -1, &sCtx.pInsert, 0
|
|
);
|
|
if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_prepare_v2(1)", db);
|
|
|
|
/* Load all files in the directory hierarchy into the FTS table. */
|
|
if( sCtx.nRowPerTrans>0 ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
|
|
traverse(zDir, (void*)&sCtx, visit_file);
|
|
if( sCtx.nRowPerTrans>0 ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
|
|
|
|
/* Clean up and exit. */
|
|
sqlite3_finalize(sCtx.pInsert);
|
|
sqlite3_close(db);
|
|
sqlite3_free(aCmd);
|
|
return 0;
|
|
}
|