]> git.pld-linux.org Git - packages/jabberd.git/commitdiff
- sqlite support for jabberd2,
authordjrzulf <djrzulf@pld-linux.org>
Tue, 4 Jan 2005 10:31:54 +0000 (10:31 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    db-setup.sqlite -> 1.1
    jabberd-2.0-sqlite.diff -> 1.1
    storage_sqlite.c -> 1.1

db-setup.sqlite [new file with mode: 0644]
jabberd-2.0-sqlite.diff [new file with mode: 0644]
storage_sqlite.c [new file with mode: 0644]

diff --git a/db-setup.sqlite b/db-setup.sqlite
new file mode 100644 (file)
index 0000000..3d2b669
--- /dev/null
@@ -0,0 +1,170 @@
+--
+-- This is the required schema for sqlite.
+--
+--     sqlite3 jabberd2.db <  db-setup.sqlite
+--
+
+--
+-- c2s authentication/registration table
+--
+CREATE TABLE 'authreg' (
+    'username' TEXT,
+    'realm' TEXT,
+    'password' TEXT,
+    'token' VARCHAR(10),
+    'sequence' INTEGER,
+    'hash' VARCHAR(40) );
+
+--
+-- Session manager tables 
+--
+
+--
+-- Active (seen) users
+-- Used by: core
+--
+CREATE TABLE 'active' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'time' INT );
+
+--
+-- Logout times
+-- Used by: mod_iq_last
+--
+CREATE TABLE 'logout' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'time' INT );
+
+--
+-- Roster items
+-- Used by: mod_roster
+--
+CREATE TABLE 'roster-items' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'jid' TEXT,
+    'name' TEXT,
+    'to' BOOL,
+    'from' BOOL,
+    'ask' INTEGER );
+
+--
+-- Roster groups
+-- Used by: mod_roster
+--
+CREATE TABLE 'roster-groups' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'jid' TEXT,
+    'group' TEXT );
+
+--
+-- vCard (user profile information)
+-- Used by: mod_iq_vcard
+--
+CREATE TABLE 'vcard' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'fn' TEXT,
+    'nickname' TEXT,
+    'url' TEXT,
+    'tel' TEXT,
+    'email' TEXT,
+    'title' TEXT,
+    'role' TEXT,
+    'bday' TEXT,
+    'desc' TEXT,
+    'n-given' TEXT,
+    'n-family' TEXT,
+    'adr-street' TEXT,
+    'adr-extadd' TEXT,
+    'adr-locality' TEXT,
+    'adr-region' TEXT,
+    'adr-pcode' TEXT,
+    'adr-country' TEXT,
+    'org-orgname' TEXT,
+    'org-orgunit' TEXT );
+
+--
+-- Offline message queue
+-- Used by: mod_offline
+--
+CREATE TABLE 'queue' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'xml' TEXT );
+
+--
+-- Private XML storage
+-- Used by: mod_iq_private
+--
+CREATE TABLE 'private' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'ns' TEXT,
+    'xml' TEXT );
+
+--
+-- Message Of The Day (MOTD) messages (announcements)
+-- Used by: mod_announce
+--
+CREATE TABLE 'motd-message' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'xml' TEXT );
+
+--
+-- Times of last MOTD message for each user
+-- Used by: mod_announce
+--
+CREATE TABLE 'motd-times' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'time' INTEGER );
+
+--
+-- User-published discovery items
+-- Used by: mod_disco_publish
+--
+CREATE TABLE 'disco-items' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'jid' TEXT,
+    'name' TEXT,
+    'node' TEXT );
+
+--
+-- Default privacy list
+-- Used by: mod_privacy
+--
+CREATE TABLE 'privacy-default' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'default' TEXT );
+
+--
+-- Privacy lists
+-- Used by: mod_privacy
+--
+CREATE TABLE 'privacy-items' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'list' TEXT,
+    'type' TEXT,
+    'value' TEXT,
+    'deny' BOOL,
+    'order' INTEGER,
+    'block' INTEGER );
+
+--
+-- Vacation settings
+-- Used by: mod_vacation
+--
+CREATE TABLE 'vacation-settings' (
+    'collection-owner' TEXT NOT NULL,
+    'object-sequence' INTEGER PRIMARY KEY,
+    'start' INTEGER,
+    'end' INTEGER,
+    'message' TEXT );
diff --git a/jabberd-2.0-sqlite.diff b/jabberd-2.0-sqlite.diff
new file mode 100644 (file)
index 0000000..92db94e
--- /dev/null
@@ -0,0 +1,70 @@
+diff -ur jabberd-2.0s6.orig/configure.in jabberd-2.0s6/configure.in
+--- jabberd-2.0s6.orig/configure.in    2004-12-12 04:06:27.000000000 +0100
++++ jabberd-2.0s6/configure.in 2004-12-24 23:17:16.691948352 +0100
+@@ -190,6 +190,22 @@
+ fi
++dnl SQLite 3
++AC_ARG_ENABLE(sqlite, AC_HELP_STRING([--enable-sqlite], [enable SQLite 3 storage support (no)]),
++              want_sqlite=$enableval, want_sqlite=no)
++if test "x-$want_sqlite" = "x-yes" ; then
++    AC_CHECK_HEADERS(sqlite3.h)
++    if test "x-$ac_cv_header_sqlite3_h" = "x-yes" ; then
++        AC_CHECK_LIB(sqlite3, sqlite3_open)
++    fi
++    if test "x-$ac_cv_lib_sqlite3_sqlite3_open" != "x-yes" ; then
++        AC_MSG_ERROR([SQLite 3 library not found])
++    else
++        AC_DEFINE(STORAGE_SQLITE,1,[Define to 1 if you want to use SQLite 3 for storage.])
++    fi
++fi
++
++
+ dnl berkeley db
+ AC_ARG_ENABLE(db, AC_HELP_STRING([--enable-db], [enable Berkeley DB auth/reg/storage support (no)]),
+               want_db=$enableval, want_db=no)
+diff -ur jabberd-2.0s6.orig/sm/Makefile.am jabberd-2.0s6/sm/Makefile.am
+--- jabberd-2.0s6.orig/sm/Makefile.am  2004-04-08 08:51:23.000000000 +0200
++++ jabberd-2.0s6/sm/Makefile.am       2004-12-24 23:13:36.245461312 +0100
+@@ -19,6 +19,7 @@
+              storage_fs.c \
+              storage_mysql.c \
+              storage_pgsql.c \
++             storage_sqlite.c \
+              mod_active.c \
+              mod_announce.c \
+              mod_deliver.c \
+diff -ur jabberd-2.0s6.orig/sm/storage.c jabberd-2.0s6/sm/storage.c
+--- jabberd-2.0s6.orig/sm/storage.c    2004-11-13 17:08:33.000000000 +0100
++++ jabberd-2.0s6/sm/storage.c 2004-12-24 23:13:21.540696776 +0100
+@@ -45,6 +45,9 @@
+ #ifdef STORAGE_PGSQL
+ extern st_ret_t st_pgsql_init(st_driver_t);
+ #endif
++#ifdef STORAGE_SQLITE
++extern st_ret_t st_sqlite_init(st_driver_t);
++#endif
+ static char *st_driver_names[] = {
+ #ifdef STORAGE_DB
+@@ -59,6 +62,9 @@
+ #ifdef STORAGE_PGSQL
+     "pgsql",
+ #endif
++#ifdef STORAGE_SQLITE
++    "sqlite",
++#endif
+     NULL
+ };
+@@ -75,6 +81,9 @@
+ #ifdef STORAGE_PGSQL
+     st_pgsql_init,
+ #endif
++#ifdef STORAGE_SQLITE
++    st_sqlite_init,
++#endif
+     NULL
+ };
diff --git a/storage_sqlite.c b/storage_sqlite.c
new file mode 100644 (file)
index 0000000..9307ad2
--- /dev/null
@@ -0,0 +1,671 @@
+/*
+ * jabberd - Jabber Open Source Server
+ * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney,
+ *                         Ryan Eatmon, Robert Norris
+ * Copyright (c) 2004      Christof Meerwald
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
+ */
+
+/* Released under the GPL by Chris Parker <parkerc@i-vsn.com>, IVSN
+ * to the Jabberd project.
+ */
+
+/* Modified and updated for SQLite 3 by Christof Meerwald,
+ * http://cmeerw.org
+ */
+
+#include "sm.h"
+
+#ifdef STORAGE_SQLITE
+
+#include <sqlite3.h>
+
+/** internal structure, holds our data */
+typedef struct drvdata_st {
+    sqlite3 *db;
+    char *prefix;
+    int txn;
+} *drvdata_t;
+
+#define BLOCKSIZE (1024)
+
+
+/** internal: do and return the math and ensure it gets realloc'd */
+static int _st_sqlite_realloc (void **oblocks, int len) {
+    void *nblocks;
+    int nlen;
+
+    /* round up to standard block sizes */
+    nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE;
+
+    /* keep trying till we get it */
+    while ((nblocks = realloc(*oblocks, nlen)) == NULL) sleep (1);
+    *oblocks = nblocks;
+
+    return nlen;
+}
+
+/** this is the safety check used to make sure there's always enough mem */
+#define SQLITE_SAFE(blocks, size, len) \
+    if((size) >= (len)) \
+       len = _st_sqlite_realloc((void**)&(blocks),(size) + 1);
+
+#define SQLITE_SAFE_CAT(blocks, size, len, s1) \
+    do { \
+       SQLITE_SAFE(blocks, size + sizeof (s1) - 1, len); \
+       memcpy (&blocks[size], s1, sizeof (s1)); \
+       size += sizeof (s1) - 1; \
+    } while (0)
+
+#define SQLITE_SAFE_CAT3(blocks, size, len, s1, s2, s3) \
+    do { \
+       const unsigned int l = strlen (s2); \
+       SQLITE_SAFE(blocks, size + sizeof (s1) + l + sizeof (s2) - 2, len); \
+       memcpy (&blocks[size], s1, sizeof (s1) - 1); \
+       memcpy (&blocks[size + sizeof (s1) - 1], s2, l); \
+       memcpy (&blocks[size + sizeof (s1) - 1 + l], s3, sizeof (s3)); \
+       size += sizeof (s1) + l + sizeof (s3) - 2; \
+    } while (0)
+
+static void _st_sqlite_convert_filter_recursive (st_filter_t f, char **buf,
+                                                int *buflen, int *nbuf) {
+
+    st_filter_t scan;
+
+    switch (f->type) {
+     case st_filter_type_PAIR:
+      SQLITE_SAFE_CAT3 ((*buf), *nbuf, *buflen,
+                       "( \"", f->key, "\" = ? ) ");
+      break;
+
+     case st_filter_type_AND:
+      SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "( ");
+
+      for (scan = f->sub; scan != NULL; scan = scan->next) {
+         _st_sqlite_convert_filter_recursive (scan, buf,
+                                              buflen, nbuf);
+
+         if (scan->next != NULL) {
+             SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "AND ");
+         }
+      }
+
+      SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, ") ");
+
+      return;
+
+     case st_filter_type_OR:
+      SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "( ");
+
+      for (scan = f->sub; scan != NULL; scan = scan->next) {
+         _st_sqlite_convert_filter_recursive (scan, buf,
+                                              buflen, nbuf);
+
+         if (scan->next != NULL) {
+             SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "OR ");
+         }
+      }
+
+      SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, ") ");
+
+      return;
+
+     case st_filter_type_NOT:
+      SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "( NOT ");
+
+      _st_sqlite_convert_filter_recursive(f->sub, buf,
+                                         buflen, nbuf);
+
+      SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, ") ");
+
+      return;
+    }
+}
+
+static char *_st_sqlite_convert_filter (st_driver_t drv, const char *owner,
+                                       const char *filter) {
+
+    drvdata_t data = (drvdata_t) drv->private;
+    char *buf = NULL;
+    unsigned int buflen = 0, nbuf = 0;
+    st_filter_t f;
+
+
+    SQLITE_SAFE_CAT (buf, nbuf, buflen, "\"collection-owner\" = ?");
+
+    f = storage_filter (filter);
+    if (f == NULL) {
+       return buf;
+    }
+
+    SQLITE_SAFE_CAT (buf, nbuf, buflen, " AND ");
+
+    _st_sqlite_convert_filter_recursive (f, &buf, &buflen, &nbuf);
+
+    pool_free (f->p);
+
+    return buf;
+}
+
+static void _st_sqlite_bind_filter_recursive (st_filter_t f,
+                                             sqlite3_stmt *stmt,
+                                             unsigned int bind_off) {
+
+    st_filter_t scan;
+    unsigned int i;
+
+    switch (f->type) {
+     case st_filter_type_PAIR:
+      sqlite3_bind_text (stmt, bind_off, f->val, strlen (f->val),
+                        SQLITE_TRANSIENT);
+      break;
+
+     case st_filter_type_AND:
+      for (scan = f->sub, i = 0; scan != NULL; scan = scan->next, ++i) {
+         _st_sqlite_bind_filter_recursive (scan, stmt, bind_off + i);
+      }
+      return;
+
+     case st_filter_type_OR:
+      for (scan = f->sub, i = 0; scan != NULL; scan = scan->next, ++i) {
+         _st_sqlite_bind_filter_recursive (scan, stmt, bind_off + i);
+      }
+      return;
+
+     case st_filter_type_NOT:
+      _st_sqlite_bind_filter_recursive(f->sub, stmt, bind_off);
+      return;
+    }
+}
+
+static void _st_sqlite_bind_filter (st_driver_t drv, const char *owner,
+                                   const char *filter,
+                                   sqlite3_stmt *stmt,
+                                   unsigned int bind_off) {
+
+    drvdata_t data = (drvdata_t) drv->private;
+    st_filter_t f;
+
+
+    sqlite3_bind_text (stmt, bind_off, owner, strlen (owner),
+                      SQLITE_TRANSIENT);
+
+    f = storage_filter (filter);
+    if (f == NULL) {
+       return;
+    }
+
+    _st_sqlite_bind_filter_recursive (f, stmt, bind_off + 1);
+
+    pool_free (f->p);
+}
+
+static st_ret_t _st_sqlite_add_type (st_driver_t drv, const char *type) {
+
+    return st_SUCCESS;
+}
+
+static st_ret_t _st_sqlite_put_guts (st_driver_t drv, const char *type,
+                                    const char *owner, os_t os) {
+
+    drvdata_t data = (drvdata_t) drv->private;
+    char *left = NULL, *right = NULL;
+    unsigned int lleft = 0, lright = 0;
+    os_object_t o;
+    char *key, *cval = NULL;
+    void *val;
+    os_type_t ot;
+    char *xml;
+    int xlen;
+    char tbuf[128];
+    int res;
+
+    if (os_count (os) == 0) {
+       return st_SUCCESS;
+    }
+
+    if (data->prefix != NULL) {
+       snprintf (tbuf, sizeof (tbuf), "%s%s", data->prefix, type);
+       type = tbuf;
+    }
+
+    if (os_iter_first (os)) {
+       do {
+
+           unsigned int i = 0;
+           unsigned int nleft = 0, nright = 0;
+           sqlite3_stmt *stmt;
+
+
+           SQLITE_SAFE_CAT3 (left, nleft, lleft,
+                             "INSERT INTO \"", type,
+                             "\" ( \"collection-owner\"");
+           SQLITE_SAFE_CAT (right, nright, lright, " ) VALUES ( ?");
+
+           o = os_iter_object (os);
+           if (os_object_iter_first(o))
+               do {
+                   os_object_iter_get (o, &key, &val, &ot);
+
+                   log_debug (ZONE, "key %s val %s", key, cval);
+
+                   SQLITE_SAFE_CAT3 (left, nleft, lleft,
+                                     ", \"", key, "\"");
+
+                   SQLITE_SAFE_CAT (right, nright, lright, ", ?");
+
+               } while (os_object_iter_next (o));
+
+           SQLITE_SAFE (left, nleft + nright, lleft);
+           memcpy (&left[nleft], right, nright);
+           nleft += nright;
+           free (right);
+
+           SQLITE_SAFE_CAT (left, nleft, lleft, " )");
+
+           log_debug (ZONE, "prepared sql: %s", left);
+
+           res = sqlite3_prepare (data->db, left, strlen (left), &stmt, NULL);
+           free (left);
+           if (res != SQLITE_OK) {
+               log_write (drv->st->sm->log, LOG_ERR,
+                          "sqlite: sql insert failed: %s",
+                          sqlite3_errmsg (data->db));
+               return st_FAILED;
+           }
+
+           sqlite3_bind_text (stmt, 1, owner, strlen (owner),
+                              SQLITE_TRANSIENT);
+
+           o = os_iter_object (os);
+           if (os_object_iter_first(o))
+               do {
+                   os_object_iter_get (o, &key, &val, &ot);
+
+                   switch(ot) {
+                    case os_type_BOOLEAN:
+                     sqlite3_bind_int (stmt, i + 2, (int) val ? 1 : 0);
+                     break;
+
+                    case os_type_INTEGER:
+                     sqlite3_bind_int (stmt, i + 2, (int) val);
+                     break;
+
+                    case os_type_STRING:
+                     sqlite3_bind_text (stmt, i + 2,
+                                        (const char *) val,
+                                        strlen ((const char *) val),
+                                        SQLITE_TRANSIENT);
+                     break;
+
+                     /* !!! might not be a good idea to mark nads this way */
+                    case os_type_NAD:
+                     nad_print ((nad_t) val, 0, &xml, &xlen);
+                     cval = (char *) malloc(sizeof(char) * (xlen + 4));
+                     memcpy (&cval[3], xml, xlen + 1);
+                     memcpy (cval, "NAD", 3);
+
+                     sqlite3_bind_text (stmt, i + 2,
+                                        cval, xlen + 3, free);
+                     break;
+                   }
+
+                   i += 1;
+               } while (os_object_iter_next (o));
+
+           res = sqlite3_step (stmt);
+           if (res != SQLITE_DONE) {
+               log_write (drv->st->sm->log, LOG_ERR,
+                          "sqlite: sql insert failed: %s",
+                          sqlite3_errmsg (data->db));
+               sqlite3_finalize (stmt);
+               return st_FAILED;
+           }
+           sqlite3_finalize (stmt);
+
+       } while (os_iter_next (os));
+    }
+
+    return st_SUCCESS;
+}
+
+static st_ret_t _st_sqlite_put (st_driver_t drv, const char *type,
+                               const char *owner, os_t os) {
+
+    drvdata_t data = (drvdata_t) drv->private;
+    int res;
+    char *err_msg = NULL;
+
+    if (os_count (os) == 0) {
+       return st_SUCCESS;
+    }
+
+    if (data->txn) {
+
+       res = sqlite3_exec (data->db,
+                           "BEGIN", NULL, NULL,
+                           &err_msg);
+       if (res != SQLITE_OK) {
+           log_write (drv->st->sm->log, LOG_ERR,
+                      "sqlite: sql transaction begin failed: %s",
+                      err_msg);
+           sqlite3_free (err_msg);
+           return st_FAILED;
+       }
+    }
+
+    if (_st_sqlite_put_guts (drv, type, owner, os) != st_SUCCESS) {
+       if (data->txn) {
+           res = sqlite3_exec (data->db, "ROLLBACK",
+                               NULL, NULL, NULL);
+       }
+       return st_FAILED;
+    }
+
+    if (data->txn) {
+
+       res = sqlite3_exec (data->db, "COMMIT", NULL, NULL, &err_msg);
+       if (res != SQLITE_OK) {
+           log_write (drv->st->sm->log, LOG_ERR,
+                      "sqlite: sql transaction commit failed: %s",
+                      err_msg);
+           sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL);
+           return st_FAILED;
+       }
+    }
+    return st_SUCCESS;
+}
+
+static st_ret_t _st_sqlite_get (st_driver_t drv, const char *type,
+                               const char *owner, const char *filter,
+                               os_t *os) {
+
+    drvdata_t data = (drvdata_t) drv->private;
+    char *cond, *buf = NULL;
+    unsigned int nbuf = 0;
+    unsigned int buflen = 0;
+    int i;
+    unsigned long *lengths;
+    unsigned int num_rows = 0;
+    os_object_t o;
+    const char *val;
+    os_type_t ot;
+    int ival;
+    nad_t nad;
+    char tbuf[128];
+
+    sqlite3_stmt *stmt;
+    int result;
+
+    if (data->prefix != NULL) {
+       snprintf (tbuf, sizeof (tbuf), "%s%s", data->prefix, type);
+       type = tbuf;
+    }
+
+    cond = _st_sqlite_convert_filter (drv, owner, filter);
+
+    SQLITE_SAFE_CAT3 (buf, nbuf, buflen,
+                     "SELECT * FROM \"", type, "\" WHERE ");
+    strcpy (&buf[nbuf], cond);
+    /* ORDER BY 'object-sequence'", type, cond); */ 
+    free (cond);
+
+    log_debug (ZONE, "prepared sql: %s", buf);
+
+    result = sqlite3_prepare (data->db, buf, strlen (buf), &stmt, NULL);
+    free (buf);
+    if (result != SQLITE_OK) {
+       return st_FAILED;
+    }
+
+    _st_sqlite_bind_filter (drv, owner, filter, stmt, 1);
+
+    *os = os_new ();
+
+    do {
+
+       unsigned int num_cols;
+
+       result = sqlite3_step (stmt);
+
+       if (result != SQLITE_ROW) {
+           continue;
+       }
+
+       o = os_object_new (*os);
+       num_cols = sqlite3_data_count (stmt);
+
+       for (i = 0; i < num_cols; i++) {
+
+           const char *colname;
+           int coltype;
+
+           colname = sqlite3_column_name (stmt, i);
+
+           if (strcmp (colname, "collection-owner") == 0 ||
+               strcmp (colname, "object-sequence") == 0) {
+               continue;
+           }
+
+           coltype = sqlite3_column_type (stmt, i);
+
+           if (coltype == SQLITE_NULL) {
+               log_debug (ZONE, "coldata is NULL");
+               continue;
+           }
+
+           if (coltype == SQLITE_INTEGER) {
+               if (!strcmp (sqlite3_column_decltype (stmt, i), "BOOL")) {
+                   ot = os_type_BOOLEAN;
+               } else {
+                   ot = os_type_INTEGER;
+               }
+
+               ival = sqlite3_column_int (stmt, i);
+               os_object_put (o, colname, &ival, ot);
+
+           } else if (coltype == SQLITE3_TEXT) {
+               ot = os_type_STRING;
+
+               val = sqlite3_column_text (stmt, i);
+               os_object_put (o, colname, val, ot);
+
+           } else {
+               log_write (drv->st->sm->log,
+                          LOG_NOTICE,
+                          "sqlite: unknown field: %s:%d",
+                          colname, coltype);
+           }
+       }
+
+       num_rows++;
+
+    } while (result == SQLITE_ROW);
+
+    sqlite3_finalize (stmt);
+
+    if (num_rows == 0) {
+       return st_NOTFOUND;
+    }
+
+    return st_SUCCESS;
+}
+
+static st_ret_t _st_sqlite_delete (st_driver_t drv, const char *type,
+                                  const char *owner, const char *filter) {
+
+    drvdata_t data = (drvdata_t) drv->private;
+    char *cond, *buf = NULL;
+    unsigned int nbuf = 0;
+    unsigned int buflen = 0;
+    char tbuf[128];
+    int res;
+    sqlite3_stmt *stmt;
+
+    if (data->prefix != NULL) {
+       snprintf (tbuf, sizeof (tbuf), "%s%s", data->prefix, type);
+       type = tbuf;
+    }
+
+    cond = _st_sqlite_convert_filter (drv, owner, filter);
+    log_debug (ZONE, "generated filter: %s", cond);
+
+    SQLITE_SAFE_CAT3 (buf, nbuf, buflen,
+                     "DELETE FROM \"", type, "\" WHERE ");
+    strcpy (&buf[nbuf], cond);
+    free (cond);
+
+    log_debug (ZONE, "prepared sql: %s", buf);
+
+    res = sqlite3_prepare (data->db, buf, strlen (buf), &stmt, NULL);
+    free (buf);
+    if (res != SQLITE_OK) {
+       return st_FAILED;
+    }
+
+    _st_sqlite_bind_filter (drv, owner, filter, stmt, 1);
+
+    res = sqlite3_step (stmt);
+    if (res != SQLITE_DONE) {
+       log_write (drv->st->sm->log, LOG_ERR,
+                  "sqlite: sql delete failed: %s",
+                  sqlite3_errmsg (data->db));
+       sqlite3_finalize (stmt);
+       return st_FAILED;
+    }
+    sqlite3_finalize (stmt);
+
+    return st_SUCCESS;
+}
+
+static st_ret_t _st_sqlite_replace (st_driver_t drv, const char *type,
+                                   const char *owner, const char *filter,
+                                   os_t os) {
+
+    drvdata_t data = (drvdata_t) drv->private;
+
+    int res;
+    char *err_msg = NULL;
+
+    if (data->txn) {
+
+       res = sqlite3_exec (data->db, "BEGIN", NULL, NULL, &err_msg);
+       if (res != SQLITE_OK) {
+           log_write (drv->st->sm->log, LOG_ERR,
+                      "sqlite: sql transaction begin failed: %s",
+                      err_msg);
+           sqlite3_free (err_msg);
+           return st_FAILED;
+       }
+    }
+
+    if (_st_sqlite_delete (drv, type, owner, filter) == st_FAILED) {
+       if (data->txn) {
+           sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL);
+       }
+       return st_FAILED;
+    }
+
+    if (_st_sqlite_put_guts (drv, type, owner, os) == st_FAILED) {
+       if (data->txn) {
+           sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL);
+       }
+       return st_FAILED;
+    }
+
+    if (data->txn) {
+
+       res = sqlite3_exec (data->db, "COMMIT", NULL, NULL, &err_msg);
+
+       if (res != SQLITE_OK) {
+           log_write (drv->st->sm->log, LOG_ERR,
+                      "sqlite: sql transaction commit failed: %s",
+                      err_msg);
+           sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL);
+
+           return st_FAILED;
+       }
+    }
+
+    return st_SUCCESS;
+}
+
+static void _st_sqlite_free (st_driver_t drv) {
+
+    drvdata_t data = (drvdata_t) drv->private;
+
+    sqlite3_close (data->db);
+
+    free (data);
+}
+
+st_ret_t st_sqlite_init(st_driver_t drv) {
+
+    char *dbname;
+    sqlite3 *db;
+    drvdata_t data;
+    int ret;
+    char *busy_timeout;
+
+    dbname = config_get_one (drv->st->sm->config,
+                            "storage.sqlite.dbname", 0);
+    if (dbname == NULL) {
+       log_write (drv->st->sm->log, LOG_ERR,
+                  "sqlite: invalid driver config");
+       return st_FAILED;
+    }
+
+    ret = sqlite3_open (dbname, &db);
+    if (ret != SQLITE_OK) {
+       log_write (drv->st->sm->log, LOG_ERR,
+                  "sqlite: can't open database");
+       return st_FAILED;
+    }
+
+    data = (drvdata_t) malloc (sizeof (struct drvdata_st));
+    memset(data, 0, sizeof(struct drvdata_st));
+
+    data->db = db;
+
+    if (config_get_one (drv->st->sm->config,
+                       "storage.sqlite.transactions", 0) != NULL) {
+       data->txn = 1;
+    } else {
+       log_write (drv->st->sm->log, LOG_WARNING,
+                  "sqlite: transactions disabled");
+    }
+
+    busy_timeout = config_get_one (drv->st->sm->config,
+                                  "storage.sqlite.busy-timeout", 0);
+    if (busy_timeout != NULL) {
+       sqlite3_busy_timeout (db, atoi (busy_timeout));
+    }
+
+    data->prefix = config_get_one (drv->st->sm->config,
+                                  "storage.sqlite.prefix", 0);
+
+    drv->private = (void *) data;
+    drv->add_type = _st_sqlite_add_type;
+    drv->put = _st_sqlite_put;
+    drv->get = _st_sqlite_get;
+    drv->delete = _st_sqlite_delete;
+    drv->replace = _st_sqlite_replace;
+    drv->free = _st_sqlite_free;
+
+    return st_SUCCESS;
+}
+
+#endif
This page took 0.119861 seconds and 4 git commands to generate.