|
|
00810b |
From 34790c335fe6e5e1099c9320d7b3134398104120 Mon Sep 17 00:00:00 2001
|
|
|
00810b |
Message-Id: <34790c335fe6e5e1099c9320d7b3134398104120.1624429665.git.pmatilai@redhat.com>
|
|
|
00810b |
From: Panu Matilainen <pmatilai@redhat.com>
|
|
|
00810b |
Date: Wed, 23 Jun 2021 08:24:44 +0300
|
|
|
00810b |
Subject: [PATCH] Add read-only support for sqlite
|
|
|
00810b |
|
|
|
00810b |
Based on latest upstream sqlite backend version, chainsaw write support
|
|
|
00810b |
out and adjust for the infra differences (which there are more than a
|
|
|
00810b |
few) and add an error message instead.
|
|
|
00810b |
---
|
|
|
00810b |
configure.ac | 23 ++
|
|
|
00810b |
lib/Makefile.am | 6 +
|
|
|
00810b |
lib/backend/dbi.c | 14 +
|
|
|
00810b |
lib/backend/dbi.h | 5 +
|
|
|
00810b |
lib/backend/sqlite.c | 659 +++++++++++++++++++++++++++++++++++++++++++
|
|
|
00810b |
macros.in | 1 +
|
|
|
00810b |
6 files changed, 708 insertions(+)
|
|
|
00810b |
create mode 100644 lib/backend/sqlite.c
|
|
|
00810b |
|
|
|
00810b |
diff --git a/configure.ac b/configure.ac
|
|
|
00810b |
index 3fcb3ff20..e04aced68 100644
|
|
|
00810b |
--- a/configure.ac
|
|
|
00810b |
+++ b/configure.ac
|
|
|
00810b |
@@ -589,6 +589,29 @@ AS_IF([test "$enable_ndb" = yes],[
|
|
|
00810b |
])
|
|
|
00810b |
AM_CONDITIONAL([NDB], [test "$enable_ndb" = yes])
|
|
|
00810b |
|
|
|
00810b |
+# Check for SQLITE support
|
|
|
00810b |
+AC_ARG_ENABLE([sqlite],
|
|
|
00810b |
+ [AS_HELP_STRING([--enable-sqlite=@<:@yes/no/auto@:>@)],
|
|
|
00810b |
+ [build with sqlite rpm database format support (default=yes)])],
|
|
|
00810b |
+ [enable_sqlite="$enableval"],
|
|
|
00810b |
+ [enable_sqlite=yes])
|
|
|
00810b |
+
|
|
|
00810b |
+AS_IF([test "x$enable_sqlite" != "xno"], [
|
|
|
00810b |
+ PKG_CHECK_MODULES([SQLITE], [sqlite3 >= 3.22.0], [have_sqlite=yes], [have_sqlite=no])
|
|
|
00810b |
+ AS_IF([test "$enable_sqlite" = "yes"], [
|
|
|
00810b |
+ if test "$have_sqlite" = "no"; then
|
|
|
00810b |
+ AC_MSG_ERROR([--enable-sqlite specified, but not available])
|
|
|
00810b |
+ fi
|
|
|
00810b |
+ ])
|
|
|
00810b |
+])
|
|
|
00810b |
+
|
|
|
00810b |
+if test "x$have_sqlite" = "xyes"; then
|
|
|
00810b |
+ AC_DEFINE([WITH_SQLITE], [1], [Define if SQLITE is available])
|
|
|
00810b |
+ SQLITE_REQUIRES=sqlite
|
|
|
00810b |
+ AC_SUBST(SQLITE_REQUIRES)
|
|
|
00810b |
+fi
|
|
|
00810b |
+AM_CONDITIONAL([SQLITE], [test "x$have_sqlite" = "xyes"])
|
|
|
00810b |
+
|
|
|
00810b |
#=================
|
|
|
00810b |
# Check for LMDB support
|
|
|
00810b |
AC_ARG_ENABLE([lmdb],
|
|
|
00810b |
diff --git a/lib/Makefile.am b/lib/Makefile.am
|
|
|
00810b |
index baf3238ee..8a9fe77bd 100644
|
|
|
00810b |
--- a/lib/Makefile.am
|
|
|
00810b |
+++ b/lib/Makefile.am
|
|
|
00810b |
@@ -76,6 +76,12 @@ librpm_la_SOURCES += \
|
|
|
00810b |
backend/ndb/rpmxdb.h
|
|
|
00810b |
endif
|
|
|
00810b |
|
|
|
00810b |
+if SQLITE
|
|
|
00810b |
+AM_CPPFLAGS += $(SQLITE_CFLAGS)
|
|
|
00810b |
+librpm_la_LIBADD += $(SQLITE_LIBS)
|
|
|
00810b |
+librpm_la_SOURCES += backend/sqlite.c
|
|
|
00810b |
+endif
|
|
|
00810b |
+
|
|
|
00810b |
if LMDB
|
|
|
00810b |
AM_CPPFLAGS += $(LMDB_CFLAGS)
|
|
|
00810b |
librpm_la_LIBADD += $(LMDB_LIBS)
|
|
|
00810b |
diff --git a/lib/backend/dbi.c b/lib/backend/dbi.c
|
|
|
00810b |
index e99a5f2b2..dc3587f58 100644
|
|
|
00810b |
--- a/lib/backend/dbi.c
|
|
|
00810b |
+++ b/lib/backend/dbi.c
|
|
|
00810b |
@@ -48,6 +48,11 @@ dbDetectBackend(rpmdb rdb)
|
|
|
00810b |
if (!strcmp(db_backend, "ndb")) {
|
|
|
00810b |
rdb->db_ops = &ndb_dbops;
|
|
|
00810b |
} else
|
|
|
00810b |
+#endif
|
|
|
00810b |
+#ifdef WITH_SQLITE
|
|
|
00810b |
+ if (!strcmp(db_backend, "sqlite")) {
|
|
|
00810b |
+ rdb->db_ops = &sqlite_dbops;
|
|
|
00810b |
+ } else
|
|
|
00810b |
#endif
|
|
|
00810b |
{
|
|
|
00810b |
rdb->db_ops = &db3_dbops;
|
|
|
00810b |
@@ -75,6 +80,15 @@ dbDetectBackend(rpmdb rdb)
|
|
|
00810b |
free(path);
|
|
|
00810b |
#endif
|
|
|
00810b |
|
|
|
00810b |
+#ifdef WITH_SQLITE
|
|
|
00810b |
+ path = rstrscat(NULL, dbhome, "/rpmdb.sqlite", NULL);
|
|
|
00810b |
+ if (access(path, F_OK) == 0 && rdb->db_ops != &sqlite_dbops) {
|
|
|
00810b |
+ rdb->db_ops = &sqlite_dbops;
|
|
|
00810b |
+ rpmlog(RPMLOG_WARNING, _("Found SQLITE rpmdb.sqlite database while attempting %s backend: using sqlite backend.\n"), db_backend);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ free(path);
|
|
|
00810b |
+#endif
|
|
|
00810b |
+
|
|
|
00810b |
path = rstrscat(NULL, dbhome, "/Packages", NULL);
|
|
|
00810b |
if (access(path, F_OK) == 0 && rdb->db_ops != &db3_dbops) {
|
|
|
00810b |
rdb->db_ops = &db3_dbops;
|
|
|
00810b |
diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h
|
|
|
00810b |
index 02f49c8fd..ff2b4f974 100644
|
|
|
00810b |
--- a/lib/backend/dbi.h
|
|
|
00810b |
+++ b/lib/backend/dbi.h
|
|
|
00810b |
@@ -275,6 +275,11 @@ RPM_GNUC_INTERNAL
|
|
|
00810b |
extern struct rpmdbOps_s lmdb_dbops;
|
|
|
00810b |
#endif
|
|
|
00810b |
|
|
|
00810b |
+#if defined(WITH_SQLITE)
|
|
|
00810b |
+RPM_GNUC_INTERNAL
|
|
|
00810b |
+extern struct rpmdbOps_s sqlite_dbops;
|
|
|
00810b |
+#endif
|
|
|
00810b |
+
|
|
|
00810b |
#ifdef __cplusplus
|
|
|
00810b |
}
|
|
|
00810b |
#endif
|
|
|
00810b |
diff --git a/lib/backend/sqlite.c b/lib/backend/sqlite.c
|
|
|
00810b |
new file mode 100644
|
|
|
00810b |
index 000000000..3caeba5f0
|
|
|
00810b |
--- /dev/null
|
|
|
00810b |
+++ b/lib/backend/sqlite.c
|
|
|
00810b |
@@ -0,0 +1,659 @@
|
|
|
00810b |
+#include "system.h"
|
|
|
00810b |
+
|
|
|
00810b |
+#include <sqlite3.h>
|
|
|
00810b |
+#include <fcntl.h>
|
|
|
00810b |
+
|
|
|
00810b |
+#include <rpm/rpmlog.h>
|
|
|
00810b |
+#include <rpm/rpmfileutil.h>
|
|
|
00810b |
+#include <rpm/rpmmacro.h>
|
|
|
00810b |
+#include "lib/rpmdb_internal.h"
|
|
|
00810b |
+
|
|
|
00810b |
+#include "debug.h"
|
|
|
00810b |
+
|
|
|
00810b |
+static const int sleep_ms = 50;
|
|
|
00810b |
+
|
|
|
00810b |
+struct dbiCursor_s {
|
|
|
00810b |
+ sqlite3 *sdb;
|
|
|
00810b |
+ sqlite3_stmt *stmt;
|
|
|
00810b |
+ const char *fmt;
|
|
|
00810b |
+ int flags;
|
|
|
00810b |
+ rpmTagVal tag;
|
|
|
00810b |
+ int ctype;
|
|
|
00810b |
+ struct dbiCursor_s *subc;
|
|
|
00810b |
+
|
|
|
00810b |
+ const void *key;
|
|
|
00810b |
+ unsigned int keylen;
|
|
|
00810b |
+};
|
|
|
00810b |
+
|
|
|
00810b |
+static int sqlexec(sqlite3 *sdb, const char *fmt, ...);
|
|
|
00810b |
+
|
|
|
00810b |
+static void rpm_match3(sqlite3_context *sctx, int argc, sqlite3_value **argv)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int match = 0;
|
|
|
00810b |
+ if (argc == 3) {
|
|
|
00810b |
+ int b1len = sqlite3_value_bytes(argv[0]);
|
|
|
00810b |
+ int b2len = sqlite3_value_bytes(argv[1]);
|
|
|
00810b |
+ int n = sqlite3_value_int(argv[2]);
|
|
|
00810b |
+ if (b1len >= n && b2len >= n) {
|
|
|
00810b |
+ const char *b1 = sqlite3_value_blob(argv[0]);
|
|
|
00810b |
+ const char *b2 = sqlite3_value_blob(argv[1]);
|
|
|
00810b |
+ match = (memcmp(b1, b2, n) == 0);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ }
|
|
|
00810b |
+ sqlite3_result_int(sctx, match);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static void errCb(void *data, int err, const char *msg)
|
|
|
00810b |
+{
|
|
|
00810b |
+ rpmdb rdb = data;
|
|
|
00810b |
+ rpmlog(RPMLOG_WARNING, "%s: %s: %s\n",
|
|
|
00810b |
+ rdb->db_descr, sqlite3_errstr(err), msg);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int dbiCursorReset(dbiCursor dbc)
|
|
|
00810b |
+{
|
|
|
00810b |
+ if (dbc->stmt) {
|
|
|
00810b |
+ sqlite3_reset(dbc->stmt);
|
|
|
00810b |
+ sqlite3_clear_bindings(dbc->stmt);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ return 0;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int dbiCursorResult(dbiCursor dbc)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = sqlite3_errcode(dbc->sdb);
|
|
|
00810b |
+ int err = (rc != SQLITE_OK && rc != SQLITE_DONE && rc != SQLITE_ROW);
|
|
|
00810b |
+ if (err) {
|
|
|
00810b |
+ rpmlog(RPMLOG_ERR, "%s: %d: %s\n", sqlite3_sql(dbc->stmt),
|
|
|
00810b |
+ sqlite3_errcode(dbc->sdb), sqlite3_errmsg(dbc->sdb));
|
|
|
00810b |
+ }
|
|
|
00810b |
+ return err ? RPMRC_FAIL : RPMRC_OK;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int dbiCursorPrep(dbiCursor dbc, const char *fmt, ...)
|
|
|
00810b |
+{
|
|
|
00810b |
+ if (dbc->stmt == NULL) {
|
|
|
00810b |
+ char *cmd = NULL;
|
|
|
00810b |
+ va_list ap;
|
|
|
00810b |
+
|
|
|
00810b |
+ va_start(ap, fmt);
|
|
|
00810b |
+ cmd = sqlite3_vmprintf(fmt, ap);
|
|
|
00810b |
+ va_end(ap);
|
|
|
00810b |
+
|
|
|
00810b |
+ sqlite3_prepare_v2(dbc->sdb, cmd, -1, &dbc->stmt, NULL);
|
|
|
00810b |
+ sqlite3_free(cmd);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ dbiCursorReset(dbc);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return dbiCursorResult(dbc);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int dbiCursorBindPkg(dbiCursor dbc, unsigned int hnum,
|
|
|
00810b |
+ void *blob, unsigned int bloblen)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = 0;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (hnum)
|
|
|
00810b |
+ rc = sqlite3_bind_int(dbc->stmt, 1, hnum);
|
|
|
00810b |
+ else
|
|
|
00810b |
+ rc = sqlite3_bind_null(dbc->stmt, 1);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (blob) {
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ rc = sqlite3_bind_blob(dbc->stmt, 2, blob, bloblen, NULL);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ return dbiCursorResult(dbc);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int dbiCursorBindIdx(dbiCursor dbc, const void *key, int keylen,
|
|
|
00810b |
+ dbiIndexItem rec)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc;
|
|
|
00810b |
+ if (dbc->ctype == SQLITE_TEXT) {
|
|
|
00810b |
+ rc = sqlite3_bind_text(dbc->stmt, 1, key, keylen, NULL);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rc = sqlite3_bind_blob(dbc->stmt, 1, key, keylen, NULL);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ if (rec) {
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ rc = sqlite3_bind_int(dbc->stmt, 2, rec->hdrNum);
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ rc = sqlite3_bind_int(dbc->stmt, 3, rec->tagNum);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return dbiCursorResult(dbc);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int sqlite_init(rpmdb rdb, const char * dbhome)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = 0;
|
|
|
00810b |
+ char *dbfile = NULL;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (rdb->db_dbenv == NULL) {
|
|
|
00810b |
+ dbfile = rpmGenPath(dbhome, "rpmdb.sqlite", NULL);
|
|
|
00810b |
+ sqlite3 *sdb = NULL;
|
|
|
00810b |
+ int xx, flags = 0;
|
|
|
00810b |
+ int retry_open = 1;
|
|
|
00810b |
+
|
|
|
00810b |
+ free(rdb->db_descr);
|
|
|
00810b |
+ rdb->db_descr = xstrdup("sqlite");
|
|
|
00810b |
+
|
|
|
00810b |
+ if ((rdb->db_mode & O_ACCMODE) == O_RDONLY)
|
|
|
00810b |
+ flags |= SQLITE_OPEN_READONLY;
|
|
|
00810b |
+ else {
|
|
|
00810b |
+ rpmlog(RPMLOG_ERR,
|
|
|
00810b |
+ _("unable to open sqlite database %s for writing, sqlite support is read-only\n"), dbfile);
|
|
|
00810b |
+ rc = RPMRC_FAIL;
|
|
|
00810b |
+ goto exit;
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ while (retry_open--) {
|
|
|
00810b |
+ xx = sqlite3_open_v2(dbfile, &sdb, flags, NULL);
|
|
|
00810b |
+ /* Attempt to create if missing, discarding OPEN_READONLY (!) */
|
|
|
00810b |
+ if (xx == SQLITE_CANTOPEN && (flags & SQLITE_OPEN_READONLY)) {
|
|
|
00810b |
+ /* Sqlite allocates resources even on failure to open (!) */
|
|
|
00810b |
+ sqlite3_close(sdb);
|
|
|
00810b |
+ flags &= ~SQLITE_OPEN_READONLY;
|
|
|
00810b |
+ flags |= (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
|
|
00810b |
+ retry_open++;
|
|
|
00810b |
+ }
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ if (xx != SQLITE_OK) {
|
|
|
00810b |
+ rpmlog(RPMLOG_ERR, _("Unable to open sqlite database %s: %s\n"),
|
|
|
00810b |
+ dbfile, sqlite3_errstr(xx));
|
|
|
00810b |
+ rc = 1;
|
|
|
00810b |
+ goto exit;
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ sqlite3_create_function(sdb, "match", 3,
|
|
|
00810b |
+ (SQLITE_UTF8|SQLITE_DETERMINISTIC),
|
|
|
00810b |
+ NULL, rpm_match3, NULL, NULL);
|
|
|
00810b |
+
|
|
|
00810b |
+ sqlite3_busy_timeout(sdb, sleep_ms);
|
|
|
00810b |
+ sqlite3_config(SQLITE_CONFIG_LOG, errCb, rdb);
|
|
|
00810b |
+
|
|
|
00810b |
+ sqlexec(sdb, "PRAGMA secure_delete = OFF");
|
|
|
00810b |
+ sqlexec(sdb, "PRAGMA case_sensitive_like = ON");
|
|
|
00810b |
+
|
|
|
00810b |
+ if (sqlite3_db_readonly(sdb, NULL) == 0) {
|
|
|
00810b |
+ if (sqlexec(sdb, "PRAGMA journal_mode = WAL") == 0) {
|
|
|
00810b |
+ int one = 1;
|
|
|
00810b |
+ /* Annoying but necessary to support non-privileged readers */
|
|
|
00810b |
+ sqlite3_file_control(sdb, NULL, SQLITE_FCNTL_PERSIST_WAL, &one);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rpmExpandNumeric("%{?_flush_io}"))
|
|
|
00810b |
+ sqlexec(sdb, "PRAGMA wal_autocheckpoint = 0");
|
|
|
00810b |
+ }
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ rdb->db_dbenv = sdb;
|
|
|
00810b |
+ }
|
|
|
00810b |
+ rdb->db_opens++;
|
|
|
00810b |
+
|
|
|
00810b |
+exit:
|
|
|
00810b |
+ free(dbfile);
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int sqlite_fini(rpmdb rdb)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = 0;
|
|
|
00810b |
+ if (rdb) {
|
|
|
00810b |
+ sqlite3 *sdb = rdb->db_dbenv;
|
|
|
00810b |
+ if (rdb->db_opens > 1) {
|
|
|
00810b |
+ rdb->db_opens--;
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ if (sqlite3_db_readonly(sdb, NULL) == 0) {
|
|
|
00810b |
+ sqlexec(sdb, "PRAGMA optimize");
|
|
|
00810b |
+ sqlexec(sdb, "PRAGMA wal_checkpoint = TRUNCATE");
|
|
|
00810b |
+ }
|
|
|
00810b |
+ rdb->db_dbenv = NULL;
|
|
|
00810b |
+ int xx = sqlite3_close(sdb);
|
|
|
00810b |
+ rc = (xx != SQLITE_OK);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int sqlexec(sqlite3 *sdb, const char *fmt, ...)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = 0;
|
|
|
00810b |
+ char *cmd = NULL;
|
|
|
00810b |
+ char *err = NULL;
|
|
|
00810b |
+ va_list ap;
|
|
|
00810b |
+
|
|
|
00810b |
+ va_start(ap, fmt);
|
|
|
00810b |
+ cmd = sqlite3_vmprintf(fmt, ap);
|
|
|
00810b |
+ va_end(ap);
|
|
|
00810b |
+
|
|
|
00810b |
+ /* sqlite3_exec() doesn't seeem to honor sqlite3_busy_timeout() */
|
|
|
00810b |
+ while ((rc = sqlite3_exec(sdb, cmd, NULL, NULL, &err)) == SQLITE_BUSY) {
|
|
|
00810b |
+ usleep(sleep_ms);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ if (rc)
|
|
|
00810b |
+ rpmlog(RPMLOG_ERR, "sqlite failure: %s: %s\n", cmd, err);
|
|
|
00810b |
+ else
|
|
|
00810b |
+ rpmlog(RPMLOG_DEBUG, "%s: %d\n", cmd, rc);
|
|
|
00810b |
+
|
|
|
00810b |
+ sqlite3_free(cmd);
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc ? RPMRC_FAIL : RPMRC_OK;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int dbiExists(dbiIndex dbi)
|
|
|
00810b |
+{
|
|
|
00810b |
+ const char *col = (dbi->dbi_type == DBI_PRIMARY) ? "hnum" : "key";
|
|
|
00810b |
+ const char *tbl = dbi->dbi_file;
|
|
|
00810b |
+ int rc = sqlite3_table_column_metadata(dbi->dbi_db, NULL, tbl, col,
|
|
|
00810b |
+ NULL, NULL, NULL, NULL, NULL);
|
|
|
00810b |
+ return (rc == 0);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int init_table(dbiIndex dbi, rpmTagVal tag)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = 0;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (dbiExists(dbi))
|
|
|
00810b |
+ return 0;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (dbi->dbi_type == DBI_PRIMARY) {
|
|
|
00810b |
+ rc = sqlexec(dbi->dbi_db,
|
|
|
00810b |
+ "CREATE TABLE IF NOT EXISTS '%q' ("
|
|
|
00810b |
+ "hnum INTEGER PRIMARY KEY AUTOINCREMENT,"
|
|
|
00810b |
+ "blob BLOB NOT NULL"
|
|
|
00810b |
+ ")",
|
|
|
00810b |
+ dbi->dbi_file);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ const char *keytype = (rpmTagGetClass(tag) == RPM_STRING_CLASS) ?
|
|
|
00810b |
+ "TEXT" : "BLOB";
|
|
|
00810b |
+ rc = sqlexec(dbi->dbi_db,
|
|
|
00810b |
+ "CREATE TABLE IF NOT EXISTS '%q' ("
|
|
|
00810b |
+ "key '%q' NOT NULL, "
|
|
|
00810b |
+ "hnum INTEGER NOT NULL, "
|
|
|
00810b |
+ "idx INTEGER NOT NULL, "
|
|
|
00810b |
+ "FOREIGN KEY (hnum) REFERENCES 'Packages'(hnum)"
|
|
|
00810b |
+ ")",
|
|
|
00810b |
+ dbi->dbi_file, keytype);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ dbi->dbi_flags |= DBI_CREATED;
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int create_index(sqlite3 *sdb, const char *table, const char *col)
|
|
|
00810b |
+{
|
|
|
00810b |
+ return sqlexec(sdb,
|
|
|
00810b |
+ "CREATE INDEX IF NOT EXISTS '%s_%s_idx' ON '%q'(%s ASC)",
|
|
|
00810b |
+ table, col, table, col);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int init_index(dbiIndex dbi, rpmTagVal tag)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = 0;
|
|
|
00810b |
+
|
|
|
00810b |
+ /* Can't create on readonly database, but things will still work */
|
|
|
00810b |
+ if (sqlite3_db_readonly(dbi->dbi_db, NULL) == 1)
|
|
|
00810b |
+ return 0;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (dbi->dbi_type == DBI_SECONDARY) {
|
|
|
00810b |
+ int string = (rpmTagGetClass(tag) == RPM_STRING_CLASS);
|
|
|
00810b |
+ int array = (rpmTagGetReturnType(tag) == RPM_ARRAY_RETURN_TYPE);
|
|
|
00810b |
+ if (!rc && string)
|
|
|
00810b |
+ rc = create_index(dbi->dbi_db, dbi->dbi_file, "key");
|
|
|
00810b |
+ if (!rc && array)
|
|
|
00810b |
+ rc = create_index(dbi->dbi_db, dbi->dbi_file, "hnum");
|
|
|
00810b |
+ }
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int sqlite_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = sqlite_init(rdb, rpmdbHome(rdb));
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rc) {
|
|
|
00810b |
+ dbiIndex dbi = dbiNew(rdb, rpmtag);
|
|
|
00810b |
+ dbi->dbi_db = rdb->db_dbenv;
|
|
|
00810b |
+
|
|
|
00810b |
+ rc = init_table(dbi, rpmtag);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rc && !(rdb->db_flags & RPMDB_FLAG_REBUILD))
|
|
|
00810b |
+ rc = init_index(dbi, rpmtag);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rc && dbip)
|
|
|
00810b |
+ *dbip = dbi;
|
|
|
00810b |
+ else
|
|
|
00810b |
+ dbiFree(dbi);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int sqlite_Close(dbiIndex dbi, unsigned int flags)
|
|
|
00810b |
+{
|
|
|
00810b |
+ rpmdb rdb = dbi->dbi_rpmdb;
|
|
|
00810b |
+ int rc = 0;
|
|
|
00810b |
+ if (rdb->db_flags & RPMDB_FLAG_REBUILD)
|
|
|
00810b |
+ rc = init_index(dbi, rpmTagGetValue(dbi->dbi_file));
|
|
|
00810b |
+ sqlite_fini(dbi->dbi_rpmdb);
|
|
|
00810b |
+ dbiFree(dbi);
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int sqlite_Verify(dbiIndex dbi, unsigned int flags)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int errors = -1;
|
|
|
00810b |
+ int key_errors = -1;
|
|
|
00810b |
+ sqlite3_stmt *s = NULL;
|
|
|
00810b |
+ const char *cmd = "PRAGMA integrity_check";
|
|
|
00810b |
+
|
|
|
00810b |
+ if (dbi->dbi_type == DBI_SECONDARY)
|
|
|
00810b |
+ return RPMRC_OK;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) {
|
|
|
00810b |
+ errors = 0;
|
|
|
00810b |
+ while (sqlite3_step(s) == SQLITE_ROW) {
|
|
|
00810b |
+ const char *txt = (const char *)sqlite3_column_text(s, 0);
|
|
|
00810b |
+ if (!rstreq(txt, "ok")) {
|
|
|
00810b |
+ errors++;
|
|
|
00810b |
+ rpmlog(RPMLOG_ERR, "verify: %s\n", txt);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ }
|
|
|
00810b |
+ sqlite3_finalize(s);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db));
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ /* No point checking higher-level errors if low-level errors exist */
|
|
|
00810b |
+ if (errors)
|
|
|
00810b |
+ goto exit;
|
|
|
00810b |
+
|
|
|
00810b |
+ cmd = "PRAGMA foreign_key_check";
|
|
|
00810b |
+ if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) {
|
|
|
00810b |
+ key_errors = 0;
|
|
|
00810b |
+ while (sqlite3_step(s) == SQLITE_ROW) {
|
|
|
00810b |
+ key_errors++;
|
|
|
00810b |
+ rpmlog(RPMLOG_ERR, "verify key: %s[%lld]\n",
|
|
|
00810b |
+ sqlite3_column_text(s, 0),
|
|
|
00810b |
+ sqlite3_column_int64(s, 1));
|
|
|
00810b |
+ }
|
|
|
00810b |
+ sqlite3_finalize(s);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db));
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+exit:
|
|
|
00810b |
+
|
|
|
00810b |
+ return (errors == 0 && key_errors == 0) ? RPMRC_OK : RPMRC_FAIL;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static void sqlite_SetFSync(rpmdb rdb, int enable)
|
|
|
00810b |
+{
|
|
|
00810b |
+ if (rdb->db_dbenv) {
|
|
|
00810b |
+ sqlexec(rdb->db_dbenv,
|
|
|
00810b |
+ "PRAGMA synchronous = %s", enable ? "FULL" : "OFF");
|
|
|
00810b |
+ }
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static int sqlite_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = 0;
|
|
|
00810b |
+
|
|
|
00810b |
+ switch (ctrl) {
|
|
|
00810b |
+ case DB_CTRL_LOCK_RW:
|
|
|
00810b |
+ rc = sqlexec(rdb->db_dbenv, "SAVEPOINT 'rwlock'");
|
|
|
00810b |
+ break;
|
|
|
00810b |
+ case DB_CTRL_UNLOCK_RW:
|
|
|
00810b |
+ rc = sqlexec(rdb->db_dbenv, "RELEASE 'rwlock'");
|
|
|
00810b |
+ break;
|
|
|
00810b |
+ default:
|
|
|
00810b |
+ break;
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static dbiCursor sqlite_CursorInit(dbiIndex dbi, unsigned int flags)
|
|
|
00810b |
+{
|
|
|
00810b |
+ dbiCursor dbc = xcalloc(1, sizeof(*dbc));
|
|
|
00810b |
+ dbc->sdb = dbi->dbi_db;
|
|
|
00810b |
+ dbc->flags = flags;
|
|
|
00810b |
+ dbc->tag = rpmTagGetValue(dbi->dbi_file);
|
|
|
00810b |
+ if (rpmTagGetClass(dbc->tag) == RPM_STRING_CLASS) {
|
|
|
00810b |
+ dbc->ctype = SQLITE_TEXT;
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ dbc->ctype = SQLITE_BLOB;
|
|
|
00810b |
+ }
|
|
|
00810b |
+ if (dbc->flags & DBC_WRITE)
|
|
|
00810b |
+ sqlexec(dbc->sdb, "SAVEPOINT '%s'", dbi->dbi_file);
|
|
|
00810b |
+ return dbc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static dbiCursor sqlite_CursorFree(dbiIndex dbi, dbiCursor dbc)
|
|
|
00810b |
+{
|
|
|
00810b |
+ if (dbc) {
|
|
|
00810b |
+ sqlite3_finalize(dbc->stmt);
|
|
|
00810b |
+ if (dbc->subc)
|
|
|
00810b |
+ dbiCursorFree(dbi, dbc->subc);
|
|
|
00810b |
+ if (dbc->flags & DBC_WRITE)
|
|
|
00810b |
+ sqlexec(dbc->sdb, "RELEASE '%s'", dbi->dbi_file);
|
|
|
00810b |
+ free(dbc);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ return NULL;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum)
|
|
|
00810b |
+{
|
|
|
00810b |
+ return RPMRC_FAIL;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen)
|
|
|
00810b |
+{
|
|
|
00810b |
+ return RPMRC_FAIL;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
|
|
|
00810b |
+{
|
|
|
00810b |
+ return RPMRC_FAIL;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_stepPkg(dbiCursor dbc, unsigned char **hdrBlob, unsigned int *hdrLen)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = sqlite3_step(dbc->stmt);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (rc == SQLITE_ROW) {
|
|
|
00810b |
+ if (hdrLen)
|
|
|
00810b |
+ *hdrLen = sqlite3_column_bytes(dbc->stmt, 1);
|
|
|
00810b |
+ if (hdrBlob)
|
|
|
00810b |
+ *hdrBlob = (void *) sqlite3_column_blob(dbc->stmt, 1);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_pkgdbByKey(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q' WHERE hnum=?",
|
|
|
00810b |
+ dbi->dbi_file);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ rc = dbiCursorBindPkg(dbc, hdrNum, NULL, 0);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen);
|
|
|
00810b |
+
|
|
|
00810b |
+ return dbiCursorResult(dbc);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_pkgdbIter(dbiIndex dbi, dbiCursor dbc,
|
|
|
00810b |
+ unsigned char **hdrBlob, unsigned int *hdrLen)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = RPMRC_OK;
|
|
|
00810b |
+ if (dbc->stmt == NULL) {
|
|
|
00810b |
+ rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q'", dbi->dbi_file);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (rc == SQLITE_DONE) {
|
|
|
00810b |
+ rc = RPMRC_NOTFOUND;
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rc = dbiCursorResult(dbc);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (hdrNum) {
|
|
|
00810b |
+ rc = sqlite_pkgdbByKey(dbi, dbc, hdrNum, hdrBlob, hdrLen);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rc = sqlite_pkgdbIter(dbi, dbc, hdrBlob, hdrLen);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static unsigned int sqlite_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
|
|
|
00810b |
+{
|
|
|
00810b |
+ return sqlite3_column_int(dbc->stmt, 0);
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_idxdbByKey(dbiIndex dbi, dbiCursor dbc,
|
|
|
00810b |
+ const char *keyp, size_t keylen, int searchType,
|
|
|
00810b |
+ dbiIndexSet *set)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = RPMRC_NOTFOUND;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (searchType == DBC_PREFIX_SEARCH) {
|
|
|
00810b |
+ rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' "
|
|
|
00810b |
+ "WHERE MATCH(key,'%q',%d) "
|
|
|
00810b |
+ "ORDER BY key",
|
|
|
00810b |
+ dbi->dbi_file, keyp, keylen);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' WHERE key=?",
|
|
|
00810b |
+ dbi->dbi_file);
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ rc = dbiCursorBindIdx(dbc, keyp, keylen, NULL);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rc) {
|
|
|
00810b |
+ while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) {
|
|
|
00810b |
+ unsigned int hnum = sqlite3_column_int(dbc->stmt, 0);
|
|
|
00810b |
+ unsigned int tnum = sqlite3_column_int(dbc->stmt, 1);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (*set == NULL)
|
|
|
00810b |
+ *set = dbiIndexSetNew(5);
|
|
|
00810b |
+ dbiIndexSetAppendOne(*set, hnum, tnum, 0);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ if (rc == SQLITE_DONE) {
|
|
|
00810b |
+ rc = (*set) ? RPMRC_OK : RPMRC_NOTFOUND;
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rc = dbiCursorResult(dbc);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_idxdbIter(dbiIndex dbi, dbiCursor dbc, dbiIndexSet *set)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc = RPMRC_OK;
|
|
|
00810b |
+
|
|
|
00810b |
+ if (dbc->stmt == NULL) {
|
|
|
00810b |
+ rc = dbiCursorPrep(dbc, "SELECT DISTINCT key FROM '%q' ORDER BY key",
|
|
|
00810b |
+ dbi->dbi_file);
|
|
|
00810b |
+ if (set)
|
|
|
00810b |
+ dbc->subc = dbiCursorInit(dbi, 0);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ if (!rc)
|
|
|
00810b |
+ rc = sqlite3_step(dbc->stmt);
|
|
|
00810b |
+
|
|
|
00810b |
+ if (rc == SQLITE_ROW) {
|
|
|
00810b |
+ if (dbc->ctype == SQLITE_TEXT) {
|
|
|
00810b |
+ dbc->key = sqlite3_column_text(dbc->stmt, 0);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ dbc->key = sqlite3_column_blob(dbc->stmt, 0);
|
|
|
00810b |
+ }
|
|
|
00810b |
+ dbc->keylen = sqlite3_column_bytes(dbc->stmt, 0);
|
|
|
00810b |
+ if (dbc->subc) {
|
|
|
00810b |
+ rc = sqlite_idxdbByKey(dbi, dbc->subc, dbc->key, dbc->keylen,
|
|
|
00810b |
+ DBC_NORMAL_SEARCH, set);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rc = RPMRC_OK;
|
|
|
00810b |
+ }
|
|
|
00810b |
+ } else if (rc == SQLITE_DONE) {
|
|
|
00810b |
+ rc = RPMRC_NOTFOUND;
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rc = dbiCursorResult(dbc);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int searchType)
|
|
|
00810b |
+{
|
|
|
00810b |
+ int rc;
|
|
|
00810b |
+ if (keyp) {
|
|
|
00810b |
+ rc = sqlite_idxdbByKey(dbi, dbc, keyp, keylen, searchType, set);
|
|
|
00810b |
+ } else {
|
|
|
00810b |
+ rc = sqlite_idxdbIter(dbi, dbc, set);
|
|
|
00810b |
+ }
|
|
|
00810b |
+
|
|
|
00810b |
+ return rc;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
|
|
|
00810b |
+{
|
|
|
00810b |
+ return RPMRC_FAIL;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static rpmRC sqlite_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
|
|
|
00810b |
+{
|
|
|
00810b |
+ return RPMRC_FAIL;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+static const void * sqlite_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
|
|
|
00810b |
+{
|
|
|
00810b |
+ const void *key = NULL;
|
|
|
00810b |
+ if (dbc) {
|
|
|
00810b |
+ key = dbc->key;
|
|
|
00810b |
+ if (key && keylen)
|
|
|
00810b |
+ *keylen = dbc->keylen;
|
|
|
00810b |
+ }
|
|
|
00810b |
+ return key;
|
|
|
00810b |
+}
|
|
|
00810b |
+
|
|
|
00810b |
+struct rpmdbOps_s sqlite_dbops = {
|
|
|
00810b |
+ .open = sqlite_Open,
|
|
|
00810b |
+ .close = sqlite_Close,
|
|
|
00810b |
+ .verify = sqlite_Verify,
|
|
|
00810b |
+ .setFSync = sqlite_SetFSync,
|
|
|
00810b |
+ .ctrl = sqlite_Ctrl,
|
|
|
00810b |
+
|
|
|
00810b |
+ .cursorInit = sqlite_CursorInit,
|
|
|
00810b |
+ .cursorFree = sqlite_CursorFree,
|
|
|
00810b |
+
|
|
|
00810b |
+ .pkgdbPut = sqlite_pkgdbPut,
|
|
|
00810b |
+ .pkgdbDel = sqlite_pkgdbDel,
|
|
|
00810b |
+ .pkgdbGet = sqlite_pkgdbGet,
|
|
|
00810b |
+ .pkgdbKey = sqlite_pkgdbKey,
|
|
|
00810b |
+ .pkgdbNew = sqlite_pkgdbNew,
|
|
|
00810b |
+
|
|
|
00810b |
+ .idxdbGet = sqlite_idxdbGet,
|
|
|
00810b |
+ .idxdbPut = sqlite_idxdbPut,
|
|
|
00810b |
+ .idxdbDel = sqlite_idxdbDel,
|
|
|
00810b |
+ .idxdbKey = sqlite_idxdbKey
|
|
|
00810b |
+};
|
|
|
00810b |
+
|
|
|
00810b |
diff --git a/macros.in b/macros.in
|
|
|
00810b |
index a6069ee4d..9ad3d60ef 100644
|
|
|
00810b |
--- a/macros.in
|
|
|
00810b |
+++ b/macros.in
|
|
|
00810b |
@@ -620,6 +620,7 @@ package or when debugging this package.\
|
|
|
00810b |
# bdb Berkeley DB
|
|
|
00810b |
# lmdb Lightning Memory-mapped Database
|
|
|
00810b |
# ndb new data base format
|
|
|
00810b |
+# sqlite Sqlite database (read-only in this version!)
|
|
|
00810b |
#
|
|
|
00810b |
%_db_backend bdb
|
|
|
00810b |
|
|
|
00810b |
--
|
|
|
00810b |
2.31.1
|
|
|
00810b |
|