【问题标题】:SQLite: How embed the memvfs extension to Amalgamation?SQLite:如何将 memvfs 扩展嵌入到合并中?
【发布时间】:2018-12-03 22:22:37
【问题描述】:

我需要在内存缓冲区中加载/保存 SQLite 数据库。为此,我想将 memvfs 扩展嵌入到 sqlite3 代码中,并将其完全编译为 sqlite3.dll。

怎么做?

更新1:

我想使用 memvfs 作为临时内存缓冲区。我的程序将数据从网络加载到缓冲区,连接到这个内存缓冲区并将数据恢复到空的内存数据库中。我认为将 memvfs 包含到 sqlite 合并中会提高性能。

更新2:

如果你想使用 memvfs 扩展,请注意源代码中自述文件中的错误。使用“PRAGMA journal_mode=OFF”代替“journal_mode=NONE”

更新3:

memvfs.c 中的另一个错误 - 使用 'max' 而不是 'maxsz' 作为 URI 中的 maxsz 参数。 sqlite 开发人员仔细设置了一个 rake :(

【问题讨论】:

  • 只需将其编译为共享库并在运行时加载,或直接包含在程序中即可。这里描述的两种方法:sqlite.org/loadext.html
  • 我读过。这不起作用,因为扩展已加载到已打开的与数据库的连接中。如何在调用 sqlite3_open_v2 之前注册 memvfs?
  • 您必须先使用:memory: 或临时文件db 来加载它;这应该注册 vfs,以便在打开真正的数据库连接时可以使用它。
  • 据我所知,只能为连接句柄注册扩展。我已经尝试过创建内存数据库、加载 ext 并附加新连接 - 没有用。通常,我想将此扩展包含到 sqlite 库中,这种方式似乎更快,更合乎逻辑。你怎么看?
  • 当我使用 memvfs 方法使用 open-temp、加载模块、close-temp、open real 进行测试时,对我来说工作得很好(不过,memvfs 使用起来很痛苦,因为你必须复制一个现有数据库文件的内容到它使用的内存中。)。也许您应该更新您的帖子以显示您尝试使用的代码?

标签: sqlite vfs


【解决方案1】:

演示使用 memvfs 的测试程序:

#include <fcntl.h>
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
  sqlite3 *db;
  char *err;

  // Open an in-memory database to use as a handle for loading the memvfs extension
  if (sqlite3_open(":memory:", &db) != SQLITE_OK) {
    fprintf(stderr, "open :memory: %s\n", sqlite3_errmsg(db));
    return EXIT_FAILURE;
  }

  sqlite3_enable_load_extension(db, 1);
  if (sqlite3_load_extension(db, "./memvfs", NULL, &err) != SQLITE_OK) {
    fprintf(stderr, "load extension: %s\n", err);
    return EXIT_FAILURE;
  }

  // Done with this database
  sqlite3_close(db);

  // Read the real database into memory
  int fd = open("foo.db", O_RDONLY);
  if (fd < 0) {
    perror("open");
    return EXIT_FAILURE;
  }
  struct stat s;
  if (fstat(fd, &s) < 0) {
    perror("fstat");
    return EXIT_FAILURE;
  }
  void *memdb = sqlite3_malloc64(s.st_size);
  if (read(fd, memdb, s.st_size) != s.st_size) {
    perror("read");
    return EXIT_FAILURE;
  }
  close(fd);

  // And open that memory with memvfs now that it holds a valid database
  char *memuri = sqlite3_mprintf("file:whatever?ptr=0x%p&sz=%lld&freeonclose=1",
                                 memdb, (long long)s.st_size);
  printf("Trying to open '%s'\n", memuri);
  if (sqlite3_open_v2(memuri, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI,
                      "memvfs") != SQLITE_OK) {
    fprintf(stderr, "open memvfs: %s\n", sqlite3_errmsg(db));
    return EXIT_FAILURE;
  }
  sqlite3_free(memuri);

  // Try querying the database to show it works.
  sqlite3_stmt *stmt;
  if (sqlite3_prepare_v2(db, "SELECT b FROM test", -1, &stmt, NULL) !=
      SQLITE_OK) {
    fprintf(stderr, "prepare: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return EXIT_FAILURE;
  }

  for (int rc = sqlite3_step(stmt); rc == SQLITE_ROW; rc = sqlite3_step(stmt)) {
    printf("%d\n", sqlite3_column_int(stmt, 0));
  }

  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return 0;
}

用法:

# Create a test database to use with memvfs
$ sqlite3 foo.db
sqlite> CREATE TABLE test(b INTEGER);
sqlite> INSERT INTO test VALUES (1), (2);
sqlite> .quit
# Compile the memvfs module and test program
$ gcc -O -fPIC -shared -o memvfs.so memvfs.c
$ gcc -O -Wall -Wextra testmem.c -lsqlite3
# And run it.
$ ./a.out
Trying to open 'file:whatever?ptr=0x56653FE2B940&sz=8192&freeonclose=1'
1
2

如果您直接将其编译到程序中而不是使用可加载模块,则工作流程相同;您只需要使用正确的参数调用sqlite3_memvfs_init(),而不是使用sqlite3_load_extension()

【讨论】:

  • 非常感谢!你让我大开眼界。
猜你喜欢
  • 2021-02-02
  • 2020-09-20
  • 2018-05-02
  • 1970-01-01
  • 2014-12-13
  • 1970-01-01
  • 2020-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多