View Issue Details

IDProjectCategoryView StatusLast Update
0000011LDMud 3.3Efunspublic2018-01-29 21:57
Reporterdafire Assigned Tolars 
PrioritynormalSeverityfeatureReproducibilityN/A
Status closedResolutionfixed 
Fixed in Version3.3.713 
Summary0000011: sqlite support (patch included)
DescriptionI created a small patch to access sqlite databases from ldmud.
sqlite is in several excercises faster then mysql and since it embeds the database engine into the driver there is no need for extra daemons or stuff.
more sqlite information on http://www.hwaci.com/sw/sqlite/

you can find a experimental patch for latest 3-3 drivers on http://ff.mud.de/~dafire/sqlite
TagsNo tags attached.
Attached Files
pkg_sqlite.diff (10,992 bytes)   
diff -Nru 3-3/src/Makefile.in 3-3.sqlite/src/Makefile.in
--- 3-3/src/Makefile.in	2003-09-28 06:08:29.000000000 +0200
+++ 3-3.sqlite/src/Makefile.in	2004-03-28 17:02:18.541126536 +0200
@@ -67,7 +67,7 @@
 #
 CFLAGS= @EXTRA_CFLAGS@ $(OPTIMIZE) $(DEBUG) $(WARN) $(MPATH) $(PROFIL)
 #
-LIBS=@LIBS@ @PKGLIBS@
+LIBS=@LIBS@ @PKGLIBS@ -lsqlite
 #
 LDFLAGS=$(PROFIL) @LDFLAGS@
 #
@@ -83,7 +83,7 @@
       lex.c main.c mapping.c md5.c mempools.c mregex.c mstrings.c object.c \
       otable.c\
       parser.c parse.c pkg-alists.c pkg-mccp.c pkg-mysql.c pkg-pcre.c \
-      pkg-pgsql.c pkg-tls.c \
+      pkg-pgsql.c pkg-tls.c pkg-sqlite.c \
       ptmalloc.c port.c ptrtable.c \
       random.c regexp.c simulate.c simul_efun.c stdstrings.c \
       strfuns.c structs.c sprintf.c swap.c wiz_list.c xalloc.c 
@@ -94,7 +94,7 @@
       lex.o main.o mapping.o md5.o mempools.o mregex.o mstrings.o object.o \
       otable.o \
       parser.o parse.o pkg-alists.o pkg-mccp.o pkg-mysql.o pkg-pcre.o \
-      pkg-pgsql.o pkg-tls.o \
+      pkg-pgsql.o pkg-tls.o pkg-sqlite.o \
       ptmalloc.o port.o ptrtable.o \
       random.o regexp.o simulate.o simul_efun.o stdstrings.o \
       strfuns.o structs.o sprintf.o swap.o wiz_list.o xalloc.o @ALLOCA@ 
diff -Nru 3-3/src/config.h.in 3-3.sqlite/src/config.h.in
--- 3-3/src/config.h.in	2003-09-28 06:39:40.000000000 +0200
+++ 3-3.sqlite/src/config.h.in	2004-03-28 17:02:18.542126384 +0200
@@ -7,6 +7,8 @@
 #ifndef CONFIG_H__
 #define CONFIG_H__ 1
 
+#define USE_SQLITE
+
 /* ----------- Commandline Argument Defaults ----------
  * These options provide default settings for those options which can
  * also be set on the commandline.
diff -Nru 3-3/src/func_spec 3-3.sqlite/src/func_spec
--- 3-3/src/func_spec	2003-11-22 06:43:46.000000000 +0100
+++ 3-3.sqlite/src/func_spec	2004-03-28 17:02:18.543126232 +0200
@@ -698,6 +698,16 @@
 
 #endif /* USE_PGSQL */
 
+
+#ifdef USE_SQLITE
+
+int      sl_open(string);
+mixed    sl_exec(string);
+int      sl_insert_id();
+void     sl_close();
+
+#endif /* USE_SQLITE */
+
 #ifdef USE_TLS
 
 int     tls_query_connection_state(object default: F_THIS_OBJECT);
diff -Nru 3-3/src/lex.c 3-3.sqlite/src/lex.c
--- 3-3/src/lex.c	2004-03-28 17:00:14.063050080 +0200
+++ 3-3.sqlite/src/lex.c	2004-03-28 17:02:18.546125776 +0200
@@ -808,6 +808,9 @@
 #ifdef USE_MYSQL
     add_permanent_define("__MYSQL__", -1, string_copy("1"), MY_FALSE);
 #endif
+#ifdef USE_SQLITE
+    add_permanent_define("__SQLITE__", -1, string_copy("1"), MY_FALSE);
+#endif
 #ifdef USE_PGSQL
     add_permanent_define("__PGSQL__", -1, string_copy("1"), MY_FALSE);
 #endif
diff -Nru 3-3/src/object.c 3-3.sqlite/src/object.c
--- 3-3/src/object.c	2003-11-22 06:43:46.000000000 +0100
+++ 3-3.sqlite/src/object.c	2004-03-28 17:02:18.551125016 +0200
@@ -42,6 +42,7 @@
  *       wiz_list_t    * user;
  *       wiz_list_t    * eff_user;
  *       int             extra_num_variables;  (ifdef DEBUG)
+ *       int             open_sqlite_db (ifdef USE_SQLITE)
  *       svalue_t      * variables;
  *       unsigned long   ticks, gigaticks;
  *   }
diff -Nru 3-3/src/object.h 3-3.sqlite/src/object.h
--- 3-3/src/object.h	2003-04-14 05:12:51.000000000 +0200
+++ 3-3.sqlite/src/object.h	2004-03-28 17:02:18.551125016 +0200
@@ -49,6 +49,9 @@
     int extra_num_variables;
     /* amylaar : used to determine where to check ref counts at all... */
 #endif
+#ifdef USE_SQLITE
+    int open_sqlite_db;   /* does this object have an open sqlite db */
+#endif 
     svalue_t *variables;
       /* All variables to this object: an array of svalues, allocated
        * in a separate block.
diff -Nru 3-3/src/pkg-sqlite.c 3-3.sqlite/src/pkg-sqlite.c
--- 3-3/src/pkg-sqlite.c	1970-01-01 01:00:00.000000000 +0100
+++ 3-3.sqlite/src/pkg-sqlite.c	2004-03-28 17:02:42.996408768 +0200
@@ -0,0 +1,268 @@
+
+#include "config.h"
+#ifdef USE_SQLITE
+  
+#include <sqlite.h>
+#include "typedefs.h"
+  
+#include "my-alloca.h"
+#include <errno.h>
+#include <stddef.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "array.h"
+#include "interpret.h"
+#include "mstrings.h"
+#include "simulate.h"
+#include "svalue.h"
+#include "xalloc.h"
+#include "object.h"
+#include "stdstrings.h"
+
+typedef struct sqlite_rows_s sqlite_rows_t;
+typedef struct sqlite_dbs_s sqlite_dbs_t;
+
+/* Since we don't know the number of rows while we retrieve the
+ * rows from a query we save the data in a single-linked list first
+ * and move them into an array after the retrieval has finished 
+ */ 
+struct sqlite_rows_s 
+{
+   vector_t * row;
+   sqlite_rows_t * last;
+};
+
+/* Database connections should be bound to the object which opens 
+ * database file. We will store all database connections in a 
+ * linked list. 
+ */ 
+struct sqlite_dbs_s 
+{
+   sqlite * db;
+   object_t * obj;
+   sqlite_dbs_t * next;
+   sqlite_dbs_t * prev;
+};
+
+/* The list of database connections.
+ */ 
+static sqlite_dbs_t *head = NULL;
+  
+// HELPER FUNS
+sqlite_dbs_t *find_db (object_t * obj) 
+{
+   sqlite_dbs_t *tmp=NULL;
+   if (!head) return NULL;
+   else tmp = head;
+
+   while (tmp)
+   {
+      if (tmp->obj==obj) return tmp;
+      tmp=tmp->prev;
+   }
+   return NULL;
+}
+
+sqlite_dbs_t * new_db()
+{
+   sqlite_dbs_t *tmp;
+   tmp = pxalloc (sizeof (*tmp));
+   tmp->db=NULL;
+   tmp->obj=NULL;
+   tmp->next=NULL;
+   if (head) {
+   	head->next=tmp;
+   	tmp->prev=head;
+   	head=tmp;
+   } else {
+   	tmp->prev=NULL;
+   	head=tmp;
+   }
+   return tmp;
+}
+
+void remove_db(sqlite_dbs_t *db)
+{
+   if (db==head)
+   {
+   	if (head->prev) 
+   	{
+   		head->prev->next=NULL;
+   		head=head->prev;
+   	} else {
+   		head=NULL;
+   	}
+   } else {
+   	if (db->next) db->next->prev=db->prev;
+   	if (db->prev) db->prev->next=db->next;
+   }
+   pfree(db);
+   db=NULL;
+}
+
+// EFUNS GO FROM HERE
+svalue_t * 
+f_sl_open (svalue_t *sp) 
+{
+   string_t *file;
+   sqlite *db;
+   sqlite_dbs_t *tmp;
+   
+   file = check_valid_path(sp->u.str, current_object, STR_SQLITE_OPEN , MY_TRUE);
+   if (!file)
+   {
+      error ("file access error\n");
+      return sp;
+   }
+   
+   tmp = find_db (current_object);
+   if (tmp)
+   {
+      error ("DB already open.\n");
+      return sp;
+   }
+   db = sqlite_open (get_txt(file), 0, NULL);
+   if (!db)
+   {
+      error ("SQLITE: Could not open Database.\n");
+      return sp;
+   }
+
+   /* create a new chain link and hang on the old chain */
+   tmp=new_db();
+   tmp->db = db;
+   tmp->obj = current_object;
+   current_object->open_sqlite_db=1;
+   free_string_svalue (sp);
+   put_number (sp, 1);
+   return sp;
+}
+
+svalue_t * 
+f_sl_exec (svalue_t * sp) 
+{
+   sqlite_vm * vm;
+   const char *tail = 0;
+   char *zErrMsg = NULL;
+   char *errmsg = NULL;
+   char *sql;
+   const char **cols = 0;
+   const char **value = 0;
+   int i, pN = 0;
+   int rows = 0;
+   sqlite_rows_t *plast = NULL, *pthis = NULL;
+   sqlite_dbs_t *db=NULL;
+   vector_t * v = NULL;
+   sql = get_txt (sp->u.str);
+   
+   db = find_db (current_object);
+   if (!db) 
+   {
+      error ("No DB open.\n");
+      return sp;
+   }
+  
+   // compile the query / create vm
+   if (sqlite_compile (db->db, sql, &tail, &vm, &zErrMsg))
+   {
+      errmsg = pxalloc (strlen (zErrMsg) + 15);
+      sprintf (errmsg, "sl_exec: %s\n", zErrMsg);
+      free (zErrMsg);
+      error (errmsg);
+      pfree (errmsg);
+      return sp;
+   }
+  
+   // get all rows 
+   while (SQLITE_ROW == sqlite_step (vm, &pN, &value, &cols))
+   {
+      ++rows;
+      pthis = pxalloc (sizeof (*pthis));
+      if (plast)
+         pthis->last = plast;
+      else
+         pthis->last = NULL;
+      pthis->row = allocate_array (pN);
+      if (!pthis->row)
+      {
+         error("Out of memory.\n");
+         return sp;
+      }
+      for (i = 0; i < pN; i++)
+         if (value[i])
+            put_c_string (pthis->row->item + i, (const char *) value[i]);
+         else
+            put_number (pthis->row->item + i, 0);
+      plast = pthis;
+   }
+
+   sqlite_finalize (vm, NULL);
+   
+   free_string_svalue (sp);
+   
+   if (rows)
+   {
+      v = allocate_array (rows);
+      if (!v)
+      {
+         error("Out of memory.\n");
+         return sp;
+      }
+      while (rows--)
+      {
+         put_array (v->item + rows, pthis->row);
+         pthis = plast->last;
+    //         pfree (plast);
+         plast = pthis;
+      }
+      put_array (sp, v);
+   }
+   else
+   {
+      put_number (sp, 0);   
+   }
+  
+   return sp;
+}
+
+int
+sl_close (object_t *ob)
+{
+   sqlite_dbs_t *db=NULL;
+   db = find_db(ob);
+   if (!db) return 0;
+   sqlite_close(db->db);
+   ob->open_sqlite_db=0;
+   remove_db(db);
+   return 1;
+}
+
+svalue_t *
+f_sl_insert_id (svalue_t * sp)
+{
+  sqlite_dbs_t *db=NULL;
+  int id;
+  db=find_db(current_object);
+  if (!db)
+  {
+      error ("No DB open.\n");
+      return sp;
+   }
+   id=sqlite_last_insert_rowid(db->db);
+   sp++;
+   put_number(sp,id);
+   return sp;
+}
+
+svalue_t * 
+f_sl_close (svalue_t * sp) 
+{
+   if (!sl_close(current_object)) 
+   {
+      error ("No DB open.\n");
+   }
+   return sp;
+}
+
+#endif /* USE_SQLITE */
diff -Nru 3-3/src/pkg-sqlite.h 3-3.sqlite/src/pkg-sqlite.h
--- 3-3/src/pkg-sqlite.h	1970-01-01 01:00:00.000000000 +0100
+++ 3-3.sqlite/src/pkg-sqlite.h	2004-03-28 17:02:18.553124712 +0200
@@ -0,0 +1,2 @@
+
+int sl_close (object_t *ob);
diff -Nru 3-3/src/simulate.c 3-3.sqlite/src/simulate.c
--- 3-3/src/simulate.c	2004-03-28 17:00:14.068049320 +0200
+++ 3-3.sqlite/src/simulate.c	2004-03-28 17:02:53.389828728 +0200
@@ -53,6 +53,9 @@
 #include "mstrings.h"
 #include "object.h"
 #include "otable.h"
+#ifdef USE_SQLITE
+#include "pkg-sqlite.h"
+#endif
 #ifdef USE_TLS
 #include "pkg-tls.h"
 #endif
@@ -1905,6 +1908,9 @@
     ob->load_name = new_tabled(name);  /* but here it is */
     ob->prog = prog;
     ob->ticks = ob->gigaticks = 0;
+#ifdef USE_SQLITE
+    ob->open_sqlite_db=0;
+#endif
     ob->next_all = obj_list;
     ob->prev_all = NULL;
     if (obj_list)
@@ -2147,6 +2153,9 @@
     if (!current_object)
         fatal("clone_object() from no current_object !\n");
 #endif
+#ifdef USE_SQLITE
+    new_ob->open_sqlite_db=0;
+#endif
     new_ob->next_all = obj_list;
     new_ob->prev_all = NULL;
     if (obj_list)
@@ -2382,6 +2391,10 @@
 #ifdef CHECK_OBJECT_REF
     xallocate(shadow, sizeof(*shadow), "destructed object shadow");
 #endif /* CHECK_OBJECT_REF */
+
+#ifdef USE_SQLITE
+    if (ob->open_sqlite_db) sl_close(ob);
+#endif
     ob->time_reset = 0;
 
     /* We need the object in memory */
diff -Nru 3-3/src/string_spec 3-3.sqlite/src/string_spec
--- 3-3/src/string_spec	2003-11-22 06:43:46.000000000 +0100
+++ 3-3.sqlite/src/string_spec	2004-03-28 17:02:18.557124104 +0200
@@ -211,5 +211,8 @@
 PG_RESET_FAILED "Reset failed, connection aborted."
 SUCCESS         "success"
 #endif
+#ifdef USE_SQLITE
+SQLITE_OPEN	"sl_open"
+#endif
 
 /***************************************************************************/
pkg_sqlite.diff (10,992 bytes)   
sqlite.html (3,135 bytes)   
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
 <head>
  <title>Index of /~dafire/sqlite</title>
 </head>
 <body>
<h1>sqlite embedded sql server for ldmud 3.3</h1>
<p><h2>this is a first working version</h2></p>
<p><h3>Needed Libraries</h3>
<ul>
<li> SQLite C library <a href=http://www.hwaci.com/sw/sqlite/>http://www.hwaci.com/sw/sqlite/</a>
</ul>
<p><h3>Known Issues</h3>
<ul><li> guess there might be memory leaks
    <li> sqlite return values are not checked properly
</ul>
</p>
<p><h3>Progress</h3>
<ul>
<li><b>01-Jul-2003</b>
<ul><li>first experiments :)
</ul>
<li><b>03-Jul-2003</b>
<ul><li> Every Object can open its own db. (dbs are bound to objects)
</ul>
<li><b>14-Aug-2003</b>
<ul><li> DB's get closed when the bound object gets destroyed.
    <li> fixed some memory leaks.. should be sort of usable now
</ul>

<li><b>24-Aug-2003</b>
<ul>
	<li>sl_insert_id() returns the autoincrement value from the last insert
	<li>__SQLITE__ define predefined in all objects</li>
</ul>

<li><b>31-Aug-2003</b>
<ul>
	<li>filenames of databases are checked by valid_write</li>
</ul>

<li><b>28-Mar-2004</b>
<ul>
	<li>The list holding the database connection lost a connection sometimes (list improved)</li>
	<li>fixed a small mem leak</li>
	<li>database connections opened by clones where not closed when the object got destructed</li>
</ul>

</ul>
</p>
<p><h3>Planed Features</h3>
<ul>
<li> optional asynchron queries using callbacks
</ul>
</p>
<h3>How It Works</h3>
<h4>Included EFUNS</h4>
<ul><li>sl_open(string filename);
    <li>sl_exec(string sqlstatement);
    <li>sl_insert_id();
    <li>sl_close();
</ul>
This example uses the testmaster you find in this directory.
<pre>
<font color=red>// opens/creates the file /myfirst.db </test></font>
> slopen myfirst.db 

<font color=red>// create a table with 3 columns</font>
> sl create table firsttable ("column 1","column 2","column 3") 
data: 0  

<font color=red>// ups.. i made an error:</font>
> sl insert into firsttable (2,5,9)
*sl_exec: near "2": syntax error

<font color=red>// insert some data</font>
> sl insert into firsttable values (2,5,9)
data: 0    
> sl insert into firsttable values ("this","is","data")
data: 0    

<font color=red>// get the data back</font>
> sl select * from firsttable
data: ({ /* #1, size: 2 */
  ({ /* #2, size: 3 */
    "2",
    "5",
    "9"
  }),
  ({ /* #3, size: 3 */
    "this",
    "is",
    "data"
  })
})
</pre>

<pre><img src="/icons/blank.gif" alt="Icon "> <a href="?C=N;O=D">Name</a>                    <a href="?C=M;O=A">Last modified</a>      <a href="?C=S;O=A">Size</a>  <a href="?C=D;O=A">Description</a><hr><img src="/icons/back.gif" alt="[DIR]"> <a href="/~dafire/">Parent Directory</a>                             -   
<img src="/icons/unknown.gif" alt="[   ]"> <a href="pkg_sqlite.diff">pkg_sqlite.diff</a>         28-Mar-2004 17:05   11K  
<img src="/icons/c.gif" alt="[   ]"> <a href="test_master.c">test_master.c</a>           14-Aug-2003 23:02  8.7K  
<hr></pre>
<address>Apache/2.0.50 (Unix) mod_ssl/2.0.50 OpenSSL/0.9.6a DAV/2 PHP/4.3.7 SVN/1.0.5 Server at ff.mud.de Port 80</address>
</body></html>
sqlite.html (3,135 bytes)   
sqlite3.diff (16,467 bytes)   
diff -Naur 711-1516.U007/src/config.h.in 711-1516.U007.sqlite/src/config.h.in
--- 711-1516.U007/src/config.h.in	2005-11-08 20:58:08.000000000 +0100
+++ 711-1516.U007.sqlite/src/config.h.in	2005-11-12 01:50:32.933417636 +0100
@@ -7,6 +7,8 @@
 #ifndef CONFIG_H__
 #define CONFIG_H__ 1
 
+#define USE_SQLITE
+
 /* ----------- Commandline Argument Defaults ----------
  * These options provide default settings for those options which can
  * also be set on the commandline.
diff -Naur 711-1516.U007/src/func_spec 711-1516.U007.sqlite/src/func_spec
--- 711-1516.U007/src/func_spec	2005-11-08 20:58:08.000000000 +0100
+++ 711-1516.U007.sqlite/src/func_spec	2005-11-11 23:51:51.000000000 +0100
@@ -722,6 +722,16 @@
 
 #endif /* USE_PGSQL */
 
+
+#ifdef USE_SQLITE
+
+int      sl_open(string);
+mixed    sl_exec(string, ...);
+int      sl_insert_id();
+void     sl_close();
+
+#endif /* USE_SQLITE */
+
 #ifdef USE_TLS
 
 int     tls_query_connection_state(object default: F_THIS_OBJECT);
diff -Naur 711-1516.U007/src/lex.c 711-1516.U007.sqlite/src/lex.c
--- 711-1516.U007/src/lex.c	2005-11-08 20:58:07.000000000 +0100
+++ 711-1516.U007.sqlite/src/lex.c	2005-11-11 22:26:13.000000000 +0100
@@ -824,6 +824,9 @@
 #ifdef USE_MYSQL
     add_permanent_define("__MYSQL__", -1, string_copy("1"), MY_FALSE);
 #endif
+#ifdef USE_SQLITE
+    add_permanent_define("__SQLITE__", -1, string_copy("1"), MY_FALSE);
+#endif
 #ifdef USE_PGSQL
     add_permanent_define("__PGSQL__", -1, string_copy("1"), MY_FALSE);
 #endif
diff -Naur 711-1516.U007/src/Makefile.in 711-1516.U007.sqlite/src/Makefile.in
--- 711-1516.U007/src/Makefile.in	2005-11-08 20:58:07.000000000 +0100
+++ 711-1516.U007.sqlite/src/Makefile.in	2005-11-12 01:49:59.149728934 +0100
@@ -74,7 +74,7 @@
 #
 CFLAGS= @EXTRA_CFLAGS@ $(OPTIMIZE) $(DEBUG) $(WARN) $(MPATH) $(PROFIL)
 #
-LIBS=@LIBS@ @PKGLIBS@
+LIBS=@LIBS@ @PKGLIBS@ -lsqlite3
 #
 LDFLAGS=$(PROFIL) @LDFLAGS@
 #
@@ -90,7 +90,7 @@
       lex.c main.c mapping.c md5.c mempools.c mregex.c mstrings.c object.c \
       otable.c\
       parser.c parse.c pkg-alists.c pkg-mccp.c pkg-mysql.c pkg-pcre.c \
-      pkg-pgsql.c pkg-tls.c \
+      pkg-pgsql.c pkg-tls.c pkg-sqlite.c \
       ptmalloc.c port.c ptrtable.c \
       random.c regexp.c sha1.c simulate.c simul_efun.c stdstrings.c \
       strfuns.c structs.c sprintf.c swap.c wiz_list.c xalloc.c 
@@ -101,7 +101,7 @@
       lex.o main.o mapping.o md5.o mempools.o mregex.o mstrings.o object.o \
       otable.o \
       parser.o parse.o pkg-alists.o pkg-mccp.o pkg-mysql.o pkg-pcre.o \
-      pkg-pgsql.o pkg-tls.o \
+      pkg-pgsql.o pkg-tls.o pkg-sqlite.o \
       ptmalloc.o port.o ptrtable.o \
       random.o regexp.o sha1.o simulate.o simul_efun.o stdstrings.o \
       strfuns.o structs.o sprintf.o swap.o wiz_list.o xalloc.o @ALLOCA@ 
diff -Naur 711-1516.U007/src/object.c 711-1516.U007.sqlite/src/object.c
--- 711-1516.U007/src/object.c	2005-11-08 20:58:07.000000000 +0100
+++ 711-1516.U007.sqlite/src/object.c	2005-11-11 22:26:13.000000000 +0100
@@ -43,6 +43,7 @@
  *       wiz_list_t    * user;
  *       wiz_list_t    * eff_user;
  *       int             extra_num_variables;  (ifdef DEBUG)
+ *       int             open_sqlite_db (ifdef USE_SQLITE)
  *       svalue_t      * variables;
  *       unsigned long   ticks, gigaticks;
  *   }
diff -Naur 711-1516.U007/src/object.h 711-1516.U007.sqlite/src/object.h
--- 711-1516.U007/src/object.h	2005-11-08 20:58:07.000000000 +0100
+++ 711-1516.U007.sqlite/src/object.h	2005-11-11 22:26:13.000000000 +0100
@@ -50,6 +50,9 @@
     int extra_num_variables;
     /* amylaar : used to determine where to check ref counts at all... */
 #endif
+#ifdef USE_SQLITE
+    int open_sqlite_db;   /* does this object have an open sqlite db */
+#endif 
     svalue_t *variables;
       /* All variables to this object: an array of svalues, allocated
        * in a separate block.
diff -Naur 711-1516.U007/src/pkg-sqlite.h 711-1516.U007.sqlite/src/pkg-sqlite.h
--- 711-1516.U007/src/pkg-sqlite.h	1970-01-01 01:00:00.000000000 +0100
+++ 711-1516.U007.sqlite/src/pkg-sqlite.h	2005-11-11 22:26:13.000000000 +0100
@@ -0,0 +1,2 @@
+
+int sl_close (object_t *ob);
diff -Naur 711-1516.U007/src/simulate.c 711-1516.U007.sqlite/src/simulate.c
--- 711-1516.U007/src/simulate.c	2005-11-08 20:58:08.000000000 +0100
+++ 711-1516.U007.sqlite/src/simulate.c	2005-11-11 22:26:13.000000000 +0100
@@ -53,6 +53,9 @@
 #include "mstrings.h"
 #include "object.h"
 #include "otable.h"
+#ifdef USE_SQLITE
+#include "pkg-sqlite.h"
+#endif
 #ifdef USE_TLS
 #include "pkg-tls.h"
 #endif
@@ -2050,6 +2053,9 @@
     ob->load_name = new_tabled(name);  /* but here it is */
     ob->prog = prog;
     ob->ticks = ob->gigaticks = 0;
+#ifdef USE_SQLITE
+    ob->open_sqlite_db=0;
+#endif
     ob->next_all = obj_list;
     ob->prev_all = NULL;
     if (obj_list)
@@ -2293,6 +2299,9 @@
     if (!current_object)
         fatal("clone_object() from no current_object !\n");
 #endif
+#ifdef USE_SQLITE
+    new_ob->open_sqlite_db=0;
+#endif
     new_ob->next_all = obj_list;
     new_ob->prev_all = NULL;
     if (obj_list)
@@ -2535,6 +2544,10 @@
 #ifdef CHECK_OBJECT_REF
     xallocate(shadow, sizeof(*shadow), "destructed object shadow");
 #endif /* CHECK_OBJECT_REF */
+
+#ifdef USE_SQLITE
+    if (ob->open_sqlite_db) sl_close(ob);
+#endif
     ob->time_reset = 0;
 
     /* We need the object in memory */
diff -Naur 711-1516.U007/src/string_spec 711-1516.U007.sqlite/src/string_spec
--- 711-1516.U007/src/string_spec	2005-11-08 20:58:08.000000000 +0100
+++ 711-1516.U007.sqlite/src/string_spec	2005-11-11 22:26:13.000000000 +0100
@@ -229,5 +229,8 @@
 SUCCESS         "success"
 
 #endif
+#ifdef USE_SQLITE
+SQLITE_OPEN	"sl_open"
+#endif
 
 /***************************************************************************/
diff -Nur 711-1516.U007/src/pkg-sqlite.c 711-1516.U007.sql/src/pkg-sqlite.c
--- 711-1516.U007/src/pkg-sqlite.c	1970-01-01 01:00:00.000000000 +0100
+++ 711-1516.U007.sql/src/pkg-sqlite.c	2005-11-12 03:22:22.835804032 +0100
@@ -0,0 +1,438 @@
+
+#include "config.h"
+#ifdef USE_SQLITE
+  
+#include <sqlite3.h>
+#include "typedefs.h"
+  
+#include "my-alloca.h"
+#include <errno.h>
+#include <stddef.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "array.h"
+#include "interpret.h"
+#include "mstrings.h"
+#include "simulate.h"
+#include "svalue.h"
+#include "xalloc.h"
+#include "object.h"
+#include "stdstrings.h"
+
+typedef struct sqlite_rows_s sqlite_rows_t;
+typedef struct sqlite_dbs_s sqlite_dbs_t;
+
+/* Since we don't know the number of rows while we retrieve the
+ * rows from a query we save the data in a single-linked list first
+ * and move them into an array after the retrieval has finished 
+ */ 
+struct sqlite_rows_s 
+{
+    vector_t * row;
+    sqlite_rows_t * last;
+};
+
+/* This structure is used for error handling. In case of an error
+ * our handler gets called with a pointer to this structure.
+ */
+struct sl_exec_cleanup_s
+{
+    svalue_t head; /* push_error_handler saves the link to our
+                      handler here. */
+
+    sqlite3_stmt *stmt;
+    sqlite_rows_t *rows;
+};
+
+/* Database connections should be bound to the object which opens 
+ * database file. We will store all database connections in a 
+ * linked list. 
+ */ 
+struct sqlite_dbs_s 
+{
+    sqlite3 * db;
+    object_t * obj;
+    sqlite_dbs_t * next;
+    sqlite_dbs_t * prev;
+};
+
+/* The list of database connections.
+ */ 
+static sqlite_dbs_t *head = NULL;
+  
+// HELPER FUNS
+sqlite_dbs_t *find_db (object_t * obj) 
+{
+    sqlite_dbs_t *tmp = head;
+
+    while (tmp)
+    {
+        if (tmp->obj==obj) return tmp;
+        tmp=tmp->prev;
+    }
+    return NULL;
+}
+
+sqlite_dbs_t * new_db()
+{
+    sqlite_dbs_t *tmp;
+    tmp = pxalloc (sizeof (*tmp));
+    if(!tmp) return NULL;
+   
+    tmp->db=NULL;
+    tmp->obj=NULL;
+    tmp->next=NULL;
+    tmp->prev=head;
+    if (head) head->next=tmp;
+    head=tmp;
+   
+    return tmp;
+}
+
+void remove_db(sqlite_dbs_t *db)
+{
+    if (db==head)
+    {
+   	if (head->prev) 
+   	{
+   	    head->prev->next=NULL;
+   	    head=head->prev;
+   	}
+        else
+        {
+   	    head=NULL;
+   	}
+    }
+    else
+    {
+   	if (db->next) db->next->prev=db->prev;
+   	if (db->prev) db->prev->next=db->next;
+    }
+    pfree(db);
+}
+
+static int
+my_sqlite3_authorizer(void* data, int what, const char* arg1, const char* arg2,
+        const char* dbname, const char* view)
+{
+    /* TODO: Check them via privilege_violation resp. valid_write.
+             (Don't know, whether sqlite can handle longjmps out of
+             its code in case of an error...)
+    */
+
+    switch(what)
+    {
+        case SQLITE_PRAGMA:
+	    if(!strcasecmp(arg1, "synchronous"))
+		return SQLITE_OK;
+            return SQLITE_DENY;
+
+        case SQLITE_ATTACH:
+        case SQLITE_DETACH:
+            return SQLITE_DENY;
+	
+        default:
+            return SQLITE_OK;
+    }
+}
+
+// EFUNS GO FROM HERE
+svalue_t * 
+f_sl_open (svalue_t *sp) 
+{
+    string_t *file;
+    sqlite3 *db;
+    sqlite_dbs_t *tmp;
+    int err;
+   
+    file = check_valid_path(sp->u.str, current_object, STR_SQLITE_OPEN , MY_TRUE);
+    if (!file)
+        errorf("Illegal use of sl_open('%s')\n", get_txt(sp->u.str));
+   
+    tmp = find_db (current_object);
+    if (tmp)
+    {
+        free_mstring(file);
+        errorf("The current object already has a database open.\n");
+    }
+
+    err = sqlite3_open (get_txt(file), &db);
+    free_mstring(file);
+    if (err)
+    {
+        const char* msg = sqlite3_errmsg(db);
+        sqlite3_close(db);
+        errorf("sl_open: %s\n", msg );
+        /* NOTREACHED */
+    }
+
+    /* create a new chain link and hang on the old chain */
+    tmp=new_db(); 
+    if(!tmp)
+    {
+        sqlite3_close(db);
+        errorf("(sl_open) Out of memory: (%lu bytes)\n",
+                (unsigned long) sizeof(*tmp));
+    }
+   
+    tmp->db = db;
+    tmp->obj = current_object;
+    current_object->open_sqlite_db=1;
+
+    /* Synchronous is damn slow. Forget it. */
+    sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, NULL);
+    sqlite3_set_authorizer(db, my_sqlite3_authorizer, NULL);
+  
+    free_string_svalue (sp);
+    put_number (sp, 1);
+    return sp;
+}
+
+static void
+sl_exec_cleanup (svalue_t * arg)
+{
+    sqlite_rows_t *row;
+    struct sl_exec_cleanup_s * data;
+    
+    data = (struct sl_exec_cleanup_s *)arg;
+    
+    if(data->stmt)
+        sqlite3_finalize(data->stmt);
+
+    row = data->rows;
+    while(row)
+    {
+        sqlite_rows_t *temp;
+
+        if(row->row)
+            free_array(row->row);
+        temp = row;
+        row = row->last;
+        pfree(temp);
+    }
+
+    xfree(data);
+}
+
+svalue_t * 
+v_sl_exec (svalue_t * sp, int num_arg) 
+{
+    svalue_t *argp;
+    sqlite_dbs_t *db;
+    sqlite3_stmt *stmt;
+    const char* tail;
+    int err, rows, cols, num;
+    struct sl_exec_cleanup_s * rec_data;
+    vector_t * result;
+
+    argp = sp - num_arg + 1; /* First argument: the SQL query */
+    
+    db = find_db (current_object);
+    if (!db)
+        errorf("The current object doesn't have a database open.\n");
+
+    err = sqlite3_prepare(db->db, get_txt(argp->u.str), mstrsize(argp->u.str),
+        &stmt, &tail);
+    if(err)
+    {
+        const char* msg = sqlite3_errmsg(db->db);
+        if(stmt)
+            sqlite3_finalize(stmt);
+        errorf("sl_exec: %s\n", msg);
+        /* NOTREACHED */
+    }
+    
+    /* Now bind all parameters. */
+    for(argp++, num=1; argp <= sp; argp++, num++)
+    {
+        switch(argp->type)
+        {
+        default:
+            sqlite3_finalize(stmt);
+            errorf("Bad argument %d to sl_exec(): type %s\n",
+                num+1, typename(argp->type));
+            break; /* NOTREACHED */
+
+        case T_FLOAT:
+            sqlite3_bind_double(stmt, num, READ_DOUBLE(argp));
+            break;
+
+        case T_NUMBER:
+            sqlite3_bind_int(stmt, num, argp->u.number);
+            break;
+    
+        case T_STRING:
+            sqlite3_bind_text(stmt, num, get_txt(argp->u.str),
+                mstrsize(argp->u.str), SQLITE_STATIC);
+            break;
+        }
+    }
+    
+    rows = 0;
+    cols = sqlite3_column_count(stmt);
+
+    rec_data = xalloc(sizeof(*rec_data));
+    if(!rec_data)
+    {
+        sqlite3_finalize(stmt);
+        errorf("(sl_exec) Out of memory: (%lu bytes) for cleanup structure\n",
+            (unsigned long) sizeof(*rec_data));
+    }
+    rec_data->rows = NULL;
+    rec_data->stmt = stmt;
+    
+    push_error_handler(sl_exec_cleanup, &(rec_data->head));
+    sp = inter_sp;
+    
+    while((err = sqlite3_step(stmt)) == SQLITE_ROW)
+    {
+        int col;
+        sqlite_rows_t *this_row;
+
+        rows++;
+        this_row = pxalloc(sizeof(*this_row));
+        if(!this_row)
+            errorf("(sl_exec) Out of memory: (%lu bytes)\n",
+                (unsigned long) sizeof(*this_row));
+
+        this_row->last = rec_data->rows;
+        rec_data->rows = this_row;
+        this_row->row = NULL; /* Because allocate_array may throw an error. */
+
+        this_row->row = allocate_array(cols);
+        if(!this_row->row)
+            errorf("(sl_exec) Out of memory: row vector\n");
+    
+        for(col = 0; col < cols; col++)
+        {
+            STORE_DOUBLE_USED;
+            svalue_t * entry;
+
+            entry = this_row->row->item + col;
+
+            switch(sqlite3_column_type(stmt, col))
+            {
+            default:
+                errorf("sl_exec: Unknown type %d.\n",
+                    sqlite3_column_type(stmt, col));
+                break;
+
+            case SQLITE_BLOB:
+                errorf("sl_exec: Blob columns are not supported.\n");
+                break;
+
+            case SQLITE_INTEGER:
+                put_number(entry, sqlite3_column_int(stmt, col));
+                break;
+
+           case SQLITE_FLOAT:
+                entry->type = T_FLOAT;
+                STORE_DOUBLE(entry, sqlite3_column_double(stmt, col));
+                break;
+
+            case SQLITE_TEXT:
+                put_c_n_string(entry,
+                    sqlite3_column_text(stmt, col),
+                    sqlite3_column_bytes(stmt, col));
+                break;
+
+            case SQLITE_NULL:
+                /* All elements from this_row->row are initialized to 0. */
+                break;
+            }
+        }
+    }
+
+    sqlite3_finalize(stmt);
+    rec_data->stmt = NULL;
+    
+    switch(err)
+    {
+    default:
+        errorf("sl_exec: Unknown return code from sqlite3_step: %d.\n", err);
+        break;
+
+    case SQLITE_BUSY:
+        errorf("sl_exec: Database is locked.\n");
+        break;
+
+    case SQLITE_ERROR:
+        errorf("sl_exec: %s\n", sqlite3_errmsg(db->db));
+        break;
+
+    case SQLITE_MISUSE:
+        errorf("sl_exec: sqlite3_step was called inappropriately.\n");
+        break;
+
+    case SQLITE_DONE:
+        break;
+    }
+
+    if(rows)
+    {
+        sqlite_rows_t *this_row;
+
+        result = allocate_array(rows);
+        if(!result)
+            errorf("(sl_exec) Out of memory: result vector\n");
+
+        this_row = rec_data->rows;
+        while(rows--)
+        {
+            put_array(result->item + rows, this_row->row);
+            this_row->row = NULL;
+            this_row = this_row->last;
+        }
+    }
+    else
+        result = NULL;
+
+    // Pop arguments and our error handler.
+    // Our error handler gets called and cleans the row stuff.
+    sp = pop_n_elems(num_arg + 1, sp) + 1; 
+    	
+    if(rows)
+        put_array(sp,result);
+    else
+        put_number(sp, 0);
+
+    return sp;
+}
+
+int
+sl_close (object_t *ob)
+{
+    sqlite_dbs_t *db = find_db(ob);
+    if (!db) return 0;
+   
+    sqlite3_close(db->db);
+    ob->open_sqlite_db=0;
+    remove_db(db);
+    return 1;
+}
+
+svalue_t *
+f_sl_insert_id (svalue_t * sp)
+{
+    sqlite_dbs_t *db = find_db(current_object);
+    int id;
+   
+    if (!db)
+        errorf("The current object doesn't have a database open.\n");
+ 
+    id=sqlite3_last_insert_rowid(db->db);
+    sp++;
+    put_number(sp,id);
+    return sp;
+}
+
+svalue_t * 
+f_sl_close (svalue_t * sp) 
+{
+    if (!sl_close(current_object)) 
+        errorf("The current object doesn't have a database open.\n");
+    return sp;
+}
+
+#endif /* USE_SQLITE */
sqlite3.diff (16,467 bytes)   
sqlite3.doc.diff (6,162 bytes)   
diff -Naur alt/doc/efun/sl_close neu/doc/efun/sl_close
--- alt/doc/efun/sl_close	1970-01-01 01:00:00.000000000 +0100
+++ neu/doc/efun/sl_close	2005-11-20 23:22:20.000000000 +0100
@@ -0,0 +1,13 @@
+OPTIONAL
+SYNOPSIS
+        void sl_close()
+
+DESCRIPTION
+        Closes the SQLite database that is associated with the
+        current object.
+
+        The function is available only if the driver is compiled with
+        SQLite support. In that case, __SQLITE__ is defined.
+
+SEE ALSO
+        sl_open, sl_exec, sl_insert_id
diff -Naur alt/doc/efun/sl_exec neu/doc/efun/sl_exec
--- alt/doc/efun/sl_exec	1970-01-01 01:00:00.000000000 +0100
+++ neu/doc/efun/sl_exec	2005-11-20 23:51:45.000000000 +0100
@@ -0,0 +1,21 @@
+OPTIONAL
+SYNOPSIS
+        mixed* sl_exec(string statement, ...)
+
+DESCRIPTION
+        Executes the SQL statement <statement> for the current
+        SQLite database. The SQL statement may contain wildcards like
+        '?' and '?nnn', where 'nnn' is an integer. These wildcards
+        can be given as further parameters to sl_exec. With '?nnn'
+        the number of a specific parameter can be given, the first
+        parameter has number 1.
+
+        If the statement returns data, sl_exec returns an array
+        with each row (which is itself an array of columns) as 
+        an element.
+
+        The function is available only if the driver is compiled with
+        SQLite support. In that case, __SQLITE__ is defined.
+
+SEE ALSO
+        sl_open, sl_insert_id, sl_close
diff -Naur alt/doc/efun/sl_insert_id neu/doc/efun/sl_insert_id
--- alt/doc/efun/sl_insert_id	1970-01-01 01:00:00.000000000 +0100
+++ neu/doc/efun/sl_insert_id	2005-11-20 23:51:51.000000000 +0100
@@ -0,0 +1,14 @@
+OPTIONAL
+SYNOPSIS
+        int sl_insert_id()
+
+DESCRIPTION
+        After inserting a line into a table with an AUTO_INCREMENT field,
+        this efun can be used to return the (new) value of the AUTO_INCREMENT
+        field.
+
+        The function is available only if the driver is compiled with
+        SQLite support. In that case, __SQLITE__ is defined.
+
+SEE ALSO
+        sl_open, sl_exec, sl_close
diff -Naur alt/doc/efun/sl_open neu/doc/efun/sl_open
--- alt/doc/efun/sl_open	1970-01-01 01:00:00.000000000 +0100
+++ neu/doc/efun/sl_open	2005-11-23 20:27:23.000000000 +0100
@@ -0,0 +1,15 @@
+OPTIONAL
+SYNOPSIS
+        int sl_open(string filename)
+
+DESCRIPTION
+        Opens the file <filename> for use as a SQLite database.
+	If the file doesn't exists it will be created.
+        Only one open file per object is allowed. On success this
+        function returns 1, otherwise usually an error is thrown.
+
+        The function is available only if the driver is compiled with
+        SQLite support. In that case, __SQLITE__ is defined.
+
+SEE ALSO
+        sl_exec, sl_insert_id, sl_close
diff -Naur alt/doc/efun.de/sl_close.de neu/doc/efun.de/sl_close.de
--- alt/doc/efun.de/sl_close.de	1970-01-01 01:00:00.000000000 +0100
+++ neu/doc/efun.de/sl_close.de	2005-11-23 20:33:03.000000000 +0100
@@ -0,0 +1,14 @@
+OPTIONAL
+SYNOPSIS
+        void sl_close()
+
+BESCHREIBUNG
+        Schliesst die SQLite-Datenbank, welche vom aktuellen Objekt
+        geoeffnet wurde.
+
+        Diese Funktion ist nur verfuegbar, wenn der Driver mit SQLite-
+        Unterstuetzung compiliert wurde. In diesem Fall ist das Makro
+        __SQLITE__ definiert.
+
+SIEHE AUCH
+        sl_open, sl_exec, sl_insert_id
diff -Naur alt/doc/efun.de/sl_exec.de neu/doc/efun.de/sl_exec.de
--- alt/doc/efun.de/sl_exec.de	1970-01-01 01:00:00.000000000 +0100
+++ neu/doc/efun.de/sl_exec.de	2005-11-23 20:41:30.000000000 +0100
@@ -0,0 +1,22 @@
+OPTIONAL
+SYNOPSIS
+        mixed* sl_exec(string statement, ...)
+
+BESCHREIBUNG
+        Fuehrt den SQL-Befehl <statement> in der aktuell geoeffneten
+        SQLite-Datenbank aus. Dieser SQL-Befehl kann Wildcards wie '?'
+        nd '?nnn', wobei 'nnn' eine Zahl ist, enthalten. Diese Wildcards
+        koennen als weitere Parameter an sl_exec uebergeben werden.
+        Mit '?nnn' kann direkt die Nummer eines bestimmten Parameters
+        angegeben werden, der erste Parameter hat die Nummer 1.
+
+        Falls der SQL-Befehl Daten zurueckliefert, liefert sl_exec ein
+        Array aus den einzelnen Zeilen (welche wieder Arrays der einzelnen
+        Felder sind) zurueck.
+
+        Diese Funktion ist nur verfuegbar, wenn der Driver mit SQLite-
+        Unterstuetzung compiliert wurde. In diesem Fall ist das Makro
+        __SQLITE__ definiert.
+
+SIEHE AUCH
+        sl_open, sl_insert_id, sl_close
diff -Naur alt/doc/efun.de/sl_insert_id.de neu/doc/efun.de/sl_insert_id.de
--- alt/doc/efun.de/sl_insert_id.de	1970-01-01 01:00:00.000000000 +0100
+++ neu/doc/efun.de/sl_insert_id.de	2005-11-23 20:34:44.000000000 +0100
@@ -0,0 +1,15 @@
+OPTIONAL
+SYNOPSIS
+        int sl_insert_id()
+
+BESCHREIBUNG
+        Nachdem eine Zeile in eine Tabelle mit einer AUTO_INCREMENT-Spalte
+        eingefuegt wurde, kann man mit dieser Funktion den (neuen) Wert
+        dieses AUTO_INCREMENT-Feldes der eingefuegten Zeile abfragen.
+
+        Diese Funktion ist nur verfuegbar, wenn der Driver mit SQLite-
+        Unterstuetzung compiliert wurde. In diesem Fall ist das Makro
+        __SQLITE__ definiert.
+
+SIEHE AUCH
+        sl_open, sl_exec, sl_close
diff -Naur alt/doc/efun.de/sl_open.de neu/doc/efun.de/sl_open.de
--- alt/doc/efun.de/sl_open.de	1970-01-01 01:00:00.000000000 +0100
+++ neu/doc/efun.de/sl_open.de	2005-11-23 20:29:46.000000000 +0100
@@ -0,0 +1,17 @@
+OPTIONAL
+SYNOPSIS
+        int sl_open(string filename)
+
+BESCHREIBUNG
+        Oeffnet die Datei <filename> als SQLite-Datenbank. Falls
+        sie noch nicht existiert, wird sie erstellt. Es ist nur
+        eine geoeffnete Datenbank pro Objekt erlaubt. Im Erfolgsfalle
+        liefert diese Funktion 1 zurueck, anderenfalls wird
+        normalerweise ein Fehler ausgeloest.
+
+        Diese Funktion ist nur verfuegbar, wenn der Driver mit SQLite-
+        Unterstuetzung compiliert wurde. In diesem Fall ist das Makro
+        __SQLITE__ definiert.
+
+SIEHE AUCH
+        sl_exec, sl_insert_id, sl_close
sqlite3.doc.diff (6,162 bytes)   
sqlite3_all.diff (30,401 bytes)   
diff -Naur 3.3/doc/efun/sl_close 3.3sqlite/doc/efun/sl_close
--- 3.3/doc/efun/sl_close	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/doc/efun/sl_close	2005-12-06 00:06:06.000000000 +0100
@@ -0,0 +1,13 @@
+OPTIONAL
+SYNOPSIS
+        void sl_close()
+
+DESCRIPTION
+        Closes the SQLite database that is associated with the
+        current object.
+
+        The function is available only if the driver is compiled with
+        SQLite support. In that case, __SQLITE__ is defined.
+
+SEE ALSO
+        sl_open, sl_exec, sl_insert_id
diff -Naur 3.3/doc/efun/sl_exec 3.3sqlite/doc/efun/sl_exec
--- 3.3/doc/efun/sl_exec	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/doc/efun/sl_exec	2005-12-06 00:06:06.000000000 +0100
@@ -0,0 +1,21 @@
+OPTIONAL
+SYNOPSIS
+        mixed* sl_exec(string statement, ...)
+
+DESCRIPTION
+        Executes the SQL statement <statement> for the current
+        SQLite database. The SQL statement may contain wildcards like
+        '?' and '?nnn', where 'nnn' is an integer. These wildcards
+        can be given as further parameters to sl_exec. With '?nnn'
+        the number of a specific parameter can be given, the first
+        parameter has number 1.
+
+        If the statement returns data, sl_exec returns an array
+        with each row (which is itself an array of columns) as 
+        an element.
+
+        The function is available only if the driver is compiled with
+        SQLite support. In that case, __SQLITE__ is defined.
+
+SEE ALSO
+        sl_open, sl_insert_id, sl_close
diff -Naur 3.3/doc/efun/sl_insert_id 3.3sqlite/doc/efun/sl_insert_id
--- 3.3/doc/efun/sl_insert_id	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/doc/efun/sl_insert_id	2005-12-06 00:06:06.000000000 +0100
@@ -0,0 +1,14 @@
+OPTIONAL
+SYNOPSIS
+        int sl_insert_id()
+
+DESCRIPTION
+        After inserting a line into a table with an AUTO_INCREMENT field,
+        this efun can be used to return the (new) value of the AUTO_INCREMENT
+        field.
+
+        The function is available only if the driver is compiled with
+        SQLite support. In that case, __SQLITE__ is defined.
+
+SEE ALSO
+        sl_open, sl_exec, sl_close
diff -Naur 3.3/doc/efun/sl_open 3.3sqlite/doc/efun/sl_open
--- 3.3/doc/efun/sl_open	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/doc/efun/sl_open	2005-12-06 00:06:06.000000000 +0100
@@ -0,0 +1,15 @@
+OPTIONAL
+SYNOPSIS
+        int sl_open(string filename)
+
+DESCRIPTION
+        Opens the file <filename> for use as a SQLite database.
+        If the file doesn't exists it will be created.
+        Only one open file per object is allowed. On success this
+        function returns 1, otherwise usually an error is thrown.
+
+        The function is available only if the driver is compiled with
+        SQLite support. In that case, __SQLITE__ is defined.
+
+SEE ALSO
+        sl_exec, sl_insert_id, sl_close
diff -Naur 3.3/doc/efun.de/sl_close.de 3.3sqlite/doc/efun.de/sl_close.de
--- 3.3/doc/efun.de/sl_close.de	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/doc/efun.de/sl_close.de	2005-12-06 00:06:06.000000000 +0100
@@ -0,0 +1,14 @@
+OPTIONAL
+SYNOPSIS
+        void sl_close()
+
+BESCHREIBUNG
+        Schliesst die SQLite-Datenbank, welche vom aktuellen Objekt
+        geoeffnet wurde.
+
+        Diese Funktion ist nur verfuegbar, wenn der Driver mit SQLite-
+        Unterstuetzung compiliert wurde. In diesem Fall ist das Makro
+        __SQLITE__ definiert.
+
+SIEHE AUCH
+        sl_open, sl_exec, sl_insert_id
diff -Naur 3.3/doc/efun.de/sl_exec.de 3.3sqlite/doc/efun.de/sl_exec.de
--- 3.3/doc/efun.de/sl_exec.de	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/doc/efun.de/sl_exec.de	2005-12-06 00:06:06.000000000 +0100
@@ -0,0 +1,22 @@
+OPTIONAL
+SYNOPSIS
+        mixed* sl_exec(string statement, ...)
+
+BESCHREIBUNG
+        Fuehrt den SQL-Befehl <statement> in der aktuell geoeffneten
+        SQLite-Datenbank aus. Dieser SQL-Befehl kann Wildcards wie '?'
+        nd '?nnn', wobei 'nnn' eine Zahl ist, enthalten. Diese Wildcards
+        koennen als weitere Parameter an sl_exec uebergeben werden.
+        Mit '?nnn' kann direkt die Nummer eines bestimmten Parameters
+        angegeben werden, der erste Parameter hat die Nummer 1.
+
+        Falls der SQL-Befehl Daten zurueckliefert, liefert sl_exec ein
+        Array aus den einzelnen Zeilen (welche wieder Arrays der einzelnen
+        Felder sind) zurueck.
+
+        Diese Funktion ist nur verfuegbar, wenn der Driver mit SQLite-
+        Unterstuetzung compiliert wurde. In diesem Fall ist das Makro
+        __SQLITE__ definiert.
+
+SIEHE AUCH
+        sl_open, sl_insert_id, sl_close
diff -Naur 3.3/doc/efun.de/sl_insert_id.de 3.3sqlite/doc/efun.de/sl_insert_id.de
--- 3.3/doc/efun.de/sl_insert_id.de	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/doc/efun.de/sl_insert_id.de	2005-12-06 00:06:06.000000000 +0100
@@ -0,0 +1,15 @@
+OPTIONAL
+SYNOPSIS
+        int sl_insert_id()
+
+BESCHREIBUNG
+        Nachdem eine Zeile in eine Tabelle mit einer AUTO_INCREMENT-Spalte
+        eingefuegt wurde, kann man mit dieser Funktion den (neuen) Wert
+        dieses AUTO_INCREMENT-Feldes der eingefuegten Zeile abfragen.
+
+        Diese Funktion ist nur verfuegbar, wenn der Driver mit SQLite-
+        Unterstuetzung compiliert wurde. In diesem Fall ist das Makro
+        __SQLITE__ definiert.
+
+SIEHE AUCH
+        sl_open, sl_exec, sl_close
diff -Naur 3.3/doc/efun.de/sl_open.de 3.3sqlite/doc/efun.de/sl_open.de
--- 3.3/doc/efun.de/sl_open.de	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/doc/efun.de/sl_open.de	2005-12-06 00:06:06.000000000 +0100
@@ -0,0 +1,17 @@
+OPTIONAL
+SYNOPSIS
+        int sl_open(string filename)
+
+BESCHREIBUNG
+        Oeffnet die Datei <filename> als SQLite-Datenbank. Falls
+        sie noch nicht existiert, wird sie erstellt. Es ist nur
+        eine geoeffnete Datenbank pro Objekt erlaubt. Im Erfolgsfalle
+        liefert diese Funktion 1 zurueck, anderenfalls wird
+        normalerweise ein Fehler ausgeloest.
+
+        Diese Funktion ist nur verfuegbar, wenn der Driver mit SQLite-
+        Unterstuetzung compiliert wurde. In diesem Fall ist das Makro
+        __SQLITE__ definiert.
+
+SIEHE AUCH
+        sl_exec, sl_insert_id, sl_close
diff -Naur 3.3/src/autoconf/acconfig.h 3.3sqlite/src/autoconf/acconfig.h
--- 3.3/src/autoconf/acconfig.h	2005-06-22 14:51:58.000000000 +0200
+++ 3.3sqlite/src/autoconf/acconfig.h	2005-12-05 22:45:32.000000000 +0100
@@ -99,6 +99,12 @@
 /* Does the machine offer PostgreSQL? */
 #undef HAS_PGSQL
 
+/* Does the machine offer SQLite3? */
+#undef HAS_SQLITE3
+
+/* Does SQLite3 use pthreads? */
+#undef SQLITE3_USES_PTHREADS
+
 /* Does the machine offer GnuTLS? */
 #undef HAS_GNUTLS
 #undef HAS_GNUTLS_VERSION
diff -Naur 3.3/src/autoconf/configure.in 3.3sqlite/src/autoconf/configure.in
--- 3.3/src/autoconf/configure.in	2005-11-08 08:31:42.000000000 +0100
+++ 3.3sqlite/src/autoconf/configure.in	2005-12-06 00:01:36.000000000 +0100
@@ -120,6 +120,7 @@
 AC_MY_ARG_ENABLE(use-mccp,no,,[Enables MCCP support])
 AC_MY_ARG_ENABLE(use-mysql,no,,[Enables mySQL support])
 AC_MY_ARG_ENABLE(use-pgsql,no,,[Enables PostgreSQL support])
+AC_MY_ARG_ENABLE(use-sqlite3,no,,[Enables SQLite3 support])
 AC_MY_ARG_ENABLE(use-pthreads,no,,[enable using of threads for socket writes])
 AC_MY_ARG_ENABLE(use-pcre,yes,,[Enables PCRE: no/yes/builtin/no-builtin])
 AC_MY_ARG_ENABLE(use-deprecated,yes,,[Enables obsolete and deprecated efuns])
@@ -305,6 +306,20 @@
   enable_use_pgsql="yes"
 fi
 
+AC_UPDATE_VAR(enable_use_sqlite3)
+if test "x$enable_use_sqlite3" = "x" || test "x$enable_use_sqlite3" = "xyes"; then
+  cdef_use_sqlite3="#define"
+  sqlite3_path=
+  enable_use_sqlite3="yes"
+elif test "x$enable_use_sqlite3" = "xno"; then
+  cdef_use_sqlite3="#undef"
+  sqlite3_path=
+else
+  cdef_use_sqlite3="#define"
+  sqlite3_path="$enable_use_sqlite3"
+  enable_use_sqlite3="yes"
+fi
+
 AC_UPDATE_VAR(enable_use_tls)
 if test "x$enable_use_tls" = "x" || test "x$enable_use_tls" = "xyes"; then
   cdef_use_tls="#define"
@@ -1505,6 +1520,129 @@
   fi
 fi
 
+# ---
+
+# --- SQLite3 ---
+
+AC_CACHE_CHECK(for SQLite3,lp_cv_has_sqlite3,
+for TESTPATH in "" "$sqlite3_path" "$sqlite3_path/include" "/usr/local/sqlite3/include" "/usr/local/include/sqlite3" "/usr/include/sqlite3" "/usr/lib/sqlite3" "/usr/local/include"; do
+    saveflags="$CFLAGS"
+    if test "x$TESTPATH" != "x"; then
+        CFLAGS="$saveflags -I$TESTPATH"
+    fi
+AC_TRY_COMPILE([
+#include <sqlite3.h>
+
+sqlite3 * foo(void)
+{
+    static sqlite3 * var;
+    
+    return var;
+}
+],,
+lp_cv_has_sqlite3=yes
+if test "x$TESTPATH" != "x"; then
+    EXTRA_CFLAGS="-I$TESTPATH $EXTRA_CFLAGS"
+fi
+break;
+,
+lp_cv_has_sqlite3=no
+CFLAGS="$saveflags"
+)
+done
+)
+
+# The system has the include files - now search for the libraries.
+if test $lp_cv_has_sqlite3 = yes; then
+  saveflags="$CFLAGS"
+  AC_DEFINE(HAS_SQLITE3)
+
+  if test $enable_use_sqlite3 = yes; then
+    tmp=""
+
+
+    if test "x$sqlite3_path" = "x"; then
+        AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -lsqlite3")
+        if test "x$tmp" = "x"; then
+            if test -d "/usr/local/sqlite3/lib/sqlite3"; then
+                unset ac_cv_lib_sqlite3_main
+                CFLAGS="$saveflags -L/usr/local/sqlite3/lib/sqlite3"
+                AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -L/usr/local/sqlite3/lib/sqlite3 -lsqlite3")
+            elif test -d "/usr/local/sqlite3/lib"; then
+                unset ac_cv_lib_sqlite3_main
+                CFLAGS="$saveflags -L/usr/local/sqlite3/lib"
+                AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -L/usr/local/sqlite3/lib -lsqlite3")
+            elif test -d "/usr/local/lib"; then
+                unset ac_cv_lib_sqlite3_main
+                CFLAGS="$saveflags -L/usr/local/lib"
+                AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -L/usr/local/lib -lsqlite3")
+            elif test -d "/usr/lib/sqlite3/lib"; then
+                unset ac_cv_lib_sqlite3_main
+                CFLAGS="$saveflags -L/usr/lib/sqlite3/lib"
+                AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -L/usr/lib/sqlite3/lib -lsqlite3")
+            fi
+        fi
+    else
+        if test -d "${sqlite3_path}/lib/sqlite3"; then
+            CFLAGS="$saveflags -L${sqlite3_path}/lib/sqlite3"
+            AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -L${sqlite3_path}/lib/sqlite3 -lsqlite3")
+        elif test -d "${sqlite3_path}/lib"; then
+            CFLAGS="$saveflags -L${sqlite3_path}/lib"
+            AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -L${sqlite3_path}/lib -lsqlite3")
+        elif test -d "${sqlite3_path}"; then
+            CFLAGS="$saveflags -L$sqlite3_path"
+            AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -L$sqlite3_path -lsqlite3")
+        fi
+    fi
+
+    if test "x$tmp" = "x"; then
+        unset ac_cv_lib_sqlite3_main
+        if test -d "/usr/local/sqlite3/lib"; then
+            CFLAGS="$saveflags -L/usr/local/sqlite3/lib"
+            AC_CHECK_LIB(sqlite3,main, tmp="$PKGLIBS -L/usr/local/sqlite3/lib -lsqlite3")
+        fi
+    fi
+
+    if test "x$tmp" == "x"; then
+        echo "libsqlite3 library not found - disabling SQLite3 support"
+        AC_NOT_AVAILABLE(use-sqlite3)
+        cdef_use_sqlite3="#undef"
+        enable_use_sqlite3="no"
+        sqlite3_path=
+        lp_cv_has_sqlite3="no"
+    else
+        PKGLIBS="$tmp"
+    fi
+  fi
+
+  if test $enable_use_sqlite3 = yes; then
+      savelibs="$LIBS"
+      LIBS="$LIBS $PKGLIBS"
+      
+      # Check if it uses pthreads
+
+      AC_CHECK_LIB(sqlite3, pthread_create,
+      	   lp_cv_sqlite3_uses_pthreads=yes,
+      	   lp_cv_sqlite3_uses_pthreads=no
+      )
+
+      if test $lp_cv_sqlite3_uses_pthreads = yes ; then
+           AC_DEFINE(SQLITE3_USES_PTHREADS)
+      fi
+
+      LIBS="$savelibs"
+  fi
+
+  CFLAGS="$saveflags"
+else
+  if test $enable_use_sqlite3 = yes; then
+      AC_NOT_AVAILABLE(use-sqlite3)
+      cdef_use_sqlite3="#undef"
+      enable_use_sqlite3=no
+  fi
+fi
+# ---
+
 # --- Check if we need zlib libraries for mccp ---
 
 if test "x$enable_use_mccp" = "x" || test "x$enable_use_mccp" = "xyes"; then
@@ -2506,6 +2644,7 @@
 AC_SUBST(cdef_use_ipv6)
 AC_SUBST(cdef_use_mysql)
 AC_SUBST(cdef_use_pgsql)
+AC_SUBST(cdef_use_sqlite3)
 AC_SUBST(cdef_use_pthreads)
 AC_SUBST(cdef_use_alists)
 AC_SUBST(cdef_use_mccp)
diff -Naur 3.3/src/config.h.in 3.3sqlite/src/config.h.in
--- 3.3/src/config.h.in	2005-06-22 14:52:18.000000000 +0200
+++ 3.3sqlite/src/config.h.in	2005-12-06 00:25:12.000000000 +0100
@@ -348,6 +348,11 @@
  */
 @cdef_use_pgsql@ USE_PGSQL
 
+/* Define this if you want SQLite3 support (assuming that your host
+ * actually offers this.
+ */
+@cdef_use_sqlite3@ USE_SQLITE3
+
 /* Define this if you want alist support.
  */
 @cdef_use_alists@ USE_ALISTS
diff -Naur 3.3/src/func_spec 3.3sqlite/src/func_spec
--- 3.3/src/func_spec	2005-11-25 08:19:27.000000000 +0100
+++ 3.3sqlite/src/func_spec	2005-12-06 00:05:58.000000000 +0100
@@ -722,6 +722,16 @@
 
 #endif /* USE_PGSQL */
 
+
+#ifdef USE_SQLITE3
+
+int      sl_open(string);
+mixed    sl_exec(string, ...);
+int      sl_insert_id();
+void     sl_close();
+
+#endif /* USE_SQLITE3 */
+
 #ifdef USE_TLS
 
 int     tls_query_connection_state(object default: F_THIS_OBJECT);
diff -Naur 3.3/src/lex.c 3.3sqlite/src/lex.c
--- 3.3/src/lex.c	2005-11-08 08:31:45.000000000 +0100
+++ 3.3sqlite/src/lex.c	2005-12-06 00:05:58.000000000 +0100
@@ -824,6 +824,9 @@
 #ifdef USE_MYSQL
     add_permanent_define("__MYSQL__", -1, string_copy("1"), MY_FALSE);
 #endif
+#ifdef USE_SQLITE3
+    add_permanent_define("__SQLITE__", -1, string_copy("1"), MY_FALSE);
+#endif
 #ifdef USE_PGSQL
     add_permanent_define("__PGSQL__", -1, string_copy("1"), MY_FALSE);
 #endif
diff -Naur 3.3/src/main.c 3.3sqlite/src/main.c
--- 3.3/src/main.c	2005-06-22 14:52:18.000000000 +0200
+++ 3.3sqlite/src/main.c	2005-12-06 00:26:50.000000000 +0100
@@ -1792,6 +1792,9 @@
 #ifdef USE_PGSQL
                               , "PostgreSQL supported\n"
 #endif
+#ifdef USE_SQLITE3
+                              , "SQLite3 supported\n"
+#endif
 #ifdef USE_PTHREADS
                               , "PThreads supported\n"
 #endif
diff -Naur 3.3/src/Makefile.in 3.3sqlite/src/Makefile.in
--- 3.3/src/Makefile.in	2005-11-25 08:19:27.000000000 +0100
+++ 3.3sqlite/src/Makefile.in	2005-12-06 00:07:39.000000000 +0100
@@ -90,7 +90,7 @@
       lex.c main.c mapping.c md5.c mempools.c mregex.c mstrings.c object.c \
       otable.c\
       parser.c parse.c pkg-alists.c pkg-mccp.c pkg-mysql.c pkg-pcre.c \
-      pkg-pgsql.c pkg-tls.c \
+      pkg-pgsql.c pkg-tls.c pkg-sqlite3.c \
       ptmalloc.c port.c ptrtable.c \
       random.c regexp.c sha1.c simulate.c simul_efun.c stdstrings.c \
       strfuns.c structs.c sprintf.c swap.c wiz_list.c xalloc.c 
@@ -101,7 +101,7 @@
       lex.o main.o mapping.o md5.o mempools.o mregex.o mstrings.o object.o \
       otable.o \
       parser.o parse.o pkg-alists.o pkg-mccp.o pkg-mysql.o pkg-pcre.o \
-      pkg-pgsql.o pkg-tls.o \
+      pkg-pgsql.o pkg-tls.o pkg-sqlite3.o \
       ptmalloc.o port.o ptrtable.o \
       random.o regexp.o sha1.o simulate.o simul_efun.o stdstrings.o \
       strfuns.o structs.o sprintf.o swap.o wiz_list.o xalloc.o @ALLOCA@ 
diff -Naur 3.3/src/object.c 3.3sqlite/src/object.c
--- 3.3/src/object.c	2005-11-25 08:19:27.000000000 +0100
+++ 3.3sqlite/src/object.c	2005-12-06 00:05:58.000000000 +0100
@@ -43,6 +43,7 @@
  *       wiz_list_t    * user;
  *       wiz_list_t    * eff_user;
  *       int             extra_num_variables;  (ifdef DEBUG)
+ *       int             open_sqlite_db (ifdef USE_SQLITE3)
  *       svalue_t      * variables;
  *       unsigned long   ticks, gigaticks;
  *   }
diff -Naur 3.3/src/object.h 3.3sqlite/src/object.h
--- 3.3/src/object.h	2005-11-25 08:19:27.000000000 +0100
+++ 3.3sqlite/src/object.h	2005-12-06 00:05:58.000000000 +0100
@@ -50,6 +50,9 @@
     int extra_num_variables;
     /* amylaar : used to determine where to check ref counts at all... */
 #endif
+#ifdef USE_SQLITE3
+    int open_sqlite_db;   /* does this object have an open sqlite db */
+#endif 
     svalue_t *variables;
       /* All variables to this object: an array of svalues, allocated
        * in a separate block.
diff -Naur 3.3/src/pkg-sqlite3.c 3.3sqlite/src/pkg-sqlite3.c
--- 3.3/src/pkg-sqlite3.c	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/src/pkg-sqlite3.c	2005-12-06 00:07:14.000000000 +0100
@@ -0,0 +1,437 @@
+#include "config.h"
+#ifdef USE_SQLITE3
+  
+#include <sqlite3.h>
+#include "typedefs.h"
+  
+#include "my-alloca.h"
+#include <errno.h>
+#include <stddef.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "array.h"
+#include "interpret.h"
+#include "mstrings.h"
+#include "simulate.h"
+#include "svalue.h"
+#include "xalloc.h"
+#include "object.h"
+#include "stdstrings.h"
+
+typedef struct sqlite_rows_s sqlite_rows_t;
+typedef struct sqlite_dbs_s sqlite_dbs_t;
+
+/* Since we don't know the number of rows while we retrieve the
+ * rows from a query we save the data in a single-linked list first
+ * and move them into an array after the retrieval has finished 
+ */ 
+struct sqlite_rows_s 
+{
+    vector_t * row;
+    sqlite_rows_t * last;
+};
+
+/* This structure is used for error handling. In case of an error
+ * our handler gets called with a pointer to this structure.
+ */
+struct sl_exec_cleanup_s
+{
+    svalue_t head; /* push_error_handler saves the link to our
+                      handler here. */
+
+    sqlite3_stmt *stmt;
+    sqlite_rows_t *rows;
+};
+
+/* Database connections should be bound to the object which opens 
+ * database file. We will store all database connections in a 
+ * linked list. 
+ */ 
+struct sqlite_dbs_s 
+{
+    sqlite3 * db;
+    object_t * obj;
+    sqlite_dbs_t * next;
+    sqlite_dbs_t * prev;
+};
+
+/* The list of database connections.
+ */ 
+static sqlite_dbs_t *head = NULL;
+  
+// HELPER FUNS
+sqlite_dbs_t *find_db (object_t * obj) 
+{
+    sqlite_dbs_t *tmp = head;
+
+    while (tmp)
+    {
+        if (tmp->obj==obj) return tmp;
+        tmp=tmp->prev;
+    }
+    return NULL;
+}
+
+sqlite_dbs_t * new_db()
+{
+    sqlite_dbs_t *tmp;
+    tmp = pxalloc (sizeof (*tmp));
+    if(!tmp) return NULL;
+   
+    tmp->db=NULL;
+    tmp->obj=NULL;
+    tmp->next=NULL;
+    tmp->prev=head;
+    if (head) head->next=tmp;
+    head=tmp;
+   
+    return tmp;
+}
+
+void remove_db(sqlite_dbs_t *db)
+{
+    if (db==head)
+    {
+   	if (head->prev) 
+   	{
+   	    head->prev->next=NULL;
+   	    head=head->prev;
+   	}
+        else
+        {
+   	    head=NULL;
+   	}
+    }
+    else
+    {
+   	if (db->next) db->next->prev=db->prev;
+   	if (db->prev) db->prev->next=db->next;
+    }
+    pfree(db);
+}
+
+static int
+my_sqlite3_authorizer(void* data, int what, const char* arg1, const char* arg2,
+        const char* dbname, const char* view)
+{
+    /* TODO: Check them via privilege_violation resp. valid_write.
+             (Don't know, whether sqlite can handle longjmps out of
+             its code in case of an error...)
+    */
+
+    switch(what)
+    {
+        case SQLITE_PRAGMA:
+	    if(!strcasecmp(arg1, "synchronous"))
+		return SQLITE_OK;
+            return SQLITE_DENY;
+
+        case SQLITE_ATTACH:
+        case SQLITE_DETACH:
+            return SQLITE_DENY;
+	
+        default:
+            return SQLITE_OK;
+    }
+}
+
+// EFUNS GO FROM HERE
+svalue_t * 
+f_sl_open (svalue_t *sp) 
+{
+    string_t *file;
+    sqlite3 *db;
+    sqlite_dbs_t *tmp;
+    int err;
+   
+    file = check_valid_path(sp->u.str, current_object, STR_SQLITE_OPEN , MY_TRUE);
+    if (!file)
+        errorf("Illegal use of sl_open('%s')\n", get_txt(sp->u.str));
+   
+    tmp = find_db (current_object);
+    if (tmp)
+    {
+        free_mstring(file);
+        errorf("The current object already has a database open.\n");
+    }
+
+    err = sqlite3_open (get_txt(file), &db);
+    free_mstring(file);
+    if (err)
+    {
+        const char* msg = sqlite3_errmsg(db);
+        sqlite3_close(db);
+        errorf("sl_open: %s\n", msg );
+        /* NOTREACHED */
+    }
+
+    /* create a new chain link and hang on the old chain */
+    tmp=new_db(); 
+    if(!tmp)
+    {
+        sqlite3_close(db);
+        errorf("(sl_open) Out of memory: (%lu bytes)\n",
+                (unsigned long) sizeof(*tmp));
+    }
+   
+    tmp->db = db;
+    tmp->obj = current_object;
+    current_object->open_sqlite_db=1;
+
+    /* Synchronous is damn slow. Forget it. */
+    sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, NULL);
+    sqlite3_set_authorizer(db, my_sqlite3_authorizer, NULL);
+  
+    free_string_svalue (sp);
+    put_number (sp, 1);
+    return sp;
+}
+
+static void
+sl_exec_cleanup (svalue_t * arg)
+{
+    sqlite_rows_t *row;
+    struct sl_exec_cleanup_s * data;
+    
+    data = (struct sl_exec_cleanup_s *)arg;
+    
+    if(data->stmt)
+        sqlite3_finalize(data->stmt);
+
+    row = data->rows;
+    while(row)
+    {
+        sqlite_rows_t *temp;
+
+        if(row->row)
+            free_array(row->row);
+        temp = row;
+        row = row->last;
+        pfree(temp);
+    }
+
+    xfree(data);
+}
+
+svalue_t * 
+v_sl_exec (svalue_t * sp, int num_arg) 
+{
+    svalue_t *argp;
+    sqlite_dbs_t *db;
+    sqlite3_stmt *stmt;
+    const char* tail;
+    int err, rows, cols, num;
+    struct sl_exec_cleanup_s * rec_data;
+    vector_t * result;
+
+    argp = sp - num_arg + 1; /* First argument: the SQL query */
+    
+    db = find_db (current_object);
+    if (!db)
+        errorf("The current object doesn't have a database open.\n");
+
+    err = sqlite3_prepare(db->db, get_txt(argp->u.str), mstrsize(argp->u.str),
+        &stmt, &tail);
+    if(err)
+    {
+        const char* msg = sqlite3_errmsg(db->db);
+        if(stmt)
+            sqlite3_finalize(stmt);
+        errorf("sl_exec: %s\n", msg);
+        /* NOTREACHED */
+    }
+    
+    /* Now bind all parameters. */
+    for(argp++, num=1; argp <= sp; argp++, num++)
+    {
+        switch(argp->type)
+        {
+        default:
+            sqlite3_finalize(stmt);
+            errorf("Bad argument %d to sl_exec(): type %s\n",
+                num+1, typename(argp->type));
+            break; /* NOTREACHED */
+
+        case T_FLOAT:
+            sqlite3_bind_double(stmt, num, READ_DOUBLE(argp));
+            break;
+
+        case T_NUMBER:
+            sqlite3_bind_int(stmt, num, argp->u.number);
+            break;
+    
+        case T_STRING:
+            sqlite3_bind_text(stmt, num, get_txt(argp->u.str),
+                mstrsize(argp->u.str), SQLITE_STATIC);
+            break;
+        }
+    }
+    
+    rows = 0;
+    cols = sqlite3_column_count(stmt);
+
+    rec_data = xalloc(sizeof(*rec_data));
+    if(!rec_data)
+    {
+        sqlite3_finalize(stmt);
+        errorf("(sl_exec) Out of memory: (%lu bytes) for cleanup structure\n",
+            (unsigned long) sizeof(*rec_data));
+    }
+    rec_data->rows = NULL;
+    rec_data->stmt = stmt;
+    
+    push_error_handler(sl_exec_cleanup, &(rec_data->head));
+    sp = inter_sp;
+    
+    while((err = sqlite3_step(stmt)) == SQLITE_ROW)
+    {
+        int col;
+        sqlite_rows_t *this_row;
+
+        rows++;
+        this_row = pxalloc(sizeof(*this_row));
+        if(!this_row)
+            errorf("(sl_exec) Out of memory: (%lu bytes)\n",
+                (unsigned long) sizeof(*this_row));
+
+        this_row->last = rec_data->rows;
+        rec_data->rows = this_row;
+        this_row->row = NULL; /* Because allocate_array may throw an error. */
+
+        this_row->row = allocate_array(cols);
+        if(!this_row->row)
+            errorf("(sl_exec) Out of memory: row vector\n");
+    
+        for(col = 0; col < cols; col++)
+        {
+            STORE_DOUBLE_USED;
+            svalue_t * entry;
+
+            entry = this_row->row->item + col;
+
+            switch(sqlite3_column_type(stmt, col))
+            {
+            default:
+                errorf("sl_exec: Unknown type %d.\n",
+                    sqlite3_column_type(stmt, col));
+                break;
+
+            case SQLITE_BLOB:
+                errorf("sl_exec: Blob columns are not supported.\n");
+                break;
+
+            case SQLITE_INTEGER:
+                put_number(entry, sqlite3_column_int(stmt, col));
+                break;
+
+           case SQLITE_FLOAT:
+                entry->type = T_FLOAT;
+                STORE_DOUBLE(entry, sqlite3_column_double(stmt, col));
+                break;
+
+            case SQLITE_TEXT:
+                put_c_n_string(entry,
+                    sqlite3_column_text(stmt, col),
+                    sqlite3_column_bytes(stmt, col));
+                break;
+
+            case SQLITE_NULL:
+                /* All elements from this_row->row are initialized to 0. */
+                break;
+            }
+        }
+    }
+
+    sqlite3_finalize(stmt);
+    rec_data->stmt = NULL;
+    
+    switch(err)
+    {
+    default:
+        errorf("sl_exec: Unknown return code from sqlite3_step: %d.\n", err);
+        break;
+
+    case SQLITE_BUSY:
+        errorf("sl_exec: Database is locked.\n");
+        break;
+
+    case SQLITE_ERROR:
+        errorf("sl_exec: %s\n", sqlite3_errmsg(db->db));
+        break;
+
+    case SQLITE_MISUSE:
+        errorf("sl_exec: sqlite3_step was called inappropriately.\n");
+        break;
+
+    case SQLITE_DONE:
+        break;
+    }
+
+    if(rows)
+    {
+        sqlite_rows_t *this_row;
+
+        result = allocate_array(rows);
+        if(!result)
+            errorf("(sl_exec) Out of memory: result vector\n");
+
+        this_row = rec_data->rows;
+        while(rows--)
+        {
+            put_array(result->item + rows, this_row->row);
+            this_row->row = NULL;
+            this_row = this_row->last;
+        }
+    }
+    else
+        result = NULL;
+
+    // Pop arguments and our error handler.
+    // Our error handler gets called and cleans the row stuff.
+    sp = pop_n_elems(num_arg + 1, sp) + 1; 
+    	
+    if(rows)
+        put_array(sp,result);
+    else
+        put_number(sp, 0);
+
+    return sp;
+}
+
+int
+sl_close (object_t *ob)
+{
+    sqlite_dbs_t *db = find_db(ob);
+    if (!db) return 0;
+   
+    sqlite3_close(db->db);
+    ob->open_sqlite_db=0;
+    remove_db(db);
+    return 1;
+}
+
+svalue_t *
+f_sl_insert_id (svalue_t * sp)
+{
+    sqlite_dbs_t *db = find_db(current_object);
+    int id;
+   
+    if (!db)
+        errorf("The current object doesn't have a database open.\n");
+ 
+    id=sqlite3_last_insert_rowid(db->db);
+    sp++;
+    put_number(sp,id);
+    return sp;
+}
+
+svalue_t * 
+f_sl_close (svalue_t * sp) 
+{
+    if (!sl_close(current_object)) 
+        errorf("The current object doesn't have a database open.\n");
+    return sp;
+}
+
+#endif /* USE_SQLITE3 */
diff -Naur 3.3/src/pkg-sqlite3.h 3.3sqlite/src/pkg-sqlite3.h
--- 3.3/src/pkg-sqlite3.h	1970-01-01 01:00:00.000000000 +0100
+++ 3.3sqlite/src/pkg-sqlite3.h	2005-12-06 00:07:18.000000000 +0100
@@ -0,0 +1,5 @@
+#ifdef USE_SQLITE3
+
+int sl_close (object_t *ob);
+
+#endif /* USE_SQLITE3 */
diff -Naur 3.3/src/simulate.c 3.3sqlite/src/simulate.c
--- 3.3/src/simulate.c	2005-11-25 08:19:27.000000000 +0100
+++ 3.3sqlite/src/simulate.c	2005-12-06 00:27:40.000000000 +0100
@@ -53,6 +53,9 @@
 #include "mstrings.h"
 #include "object.h"
 #include "otable.h"
+#ifdef USE_SQLITE3
+#include "pkg-sqlite3.h"
+#endif
 #ifdef USE_TLS
 #include "pkg-tls.h"
 #endif
@@ -2059,6 +2062,9 @@
     ob->load_name = new_tabled(name);  /* but here it is */
     ob->prog = prog;
     ob->ticks = ob->gigaticks = 0;
+#ifdef USE_SQLITE3
+    ob->open_sqlite_db=0;
+#endif
     ob->next_all = obj_list;
     ob->prev_all = NULL;
     if (obj_list)
@@ -2302,6 +2308,9 @@
     if (!current_object)
         fatal("clone_object() from no current_object !\n");
 #endif
+#ifdef USE_SQLITE3
+    new_ob->open_sqlite_db=0;
+#endif
     new_ob->next_all = obj_list;
     new_ob->prev_all = NULL;
     if (obj_list)
@@ -2544,6 +2553,10 @@
 #ifdef CHECK_OBJECT_REF
     xallocate(shadow, sizeof(*shadow), "destructed object shadow");
 #endif /* CHECK_OBJECT_REF */
+
+#ifdef USE_SQLITE3
+    if (ob->open_sqlite_db) sl_close(ob);
+#endif
     ob->time_reset = 0;
 
     /* We need the object in memory */
diff -Naur 3.3/src/slaballoc.c 3.3sqlite/src/slaballoc.c
--- 3.3/src/slaballoc.c	2005-06-22 14:52:18.000000000 +0200
+++ 3.3sqlite/src/slaballoc.c	2005-12-06 00:13:39.000000000 +0100
@@ -230,7 +230,7 @@
 
 #if defined(SBRK_OK)
 #  ifdef MALLOC_SBRK
-#      if !defined(USE_PTHREADS)
+#      if !defined(USE_PTHREADS) && (!defined(USE_SQLITE3) || !defined(SQLITE3_USES_PTHREADS))
 #          define REPLACE_MALLOC
 #      else
 #          undef SBRK_OK
diff -Naur 3.3/src/smalloc.c 3.3sqlite/src/smalloc.c
--- 3.3/src/smalloc.c	2005-11-08 08:31:45.000000000 +0100
+++ 3.3sqlite/src/smalloc.c	2005-12-06 00:13:18.000000000 +0100
@@ -243,7 +243,7 @@
 
 #if defined(SBRK_OK)
 #  ifdef MALLOC_SBRK
-#      if !defined(USE_PTHREADS)
+#      if !defined(USE_PTHREADS) && (!defined(USE_SQLITE3) || !defined(SQLITE3_USES_PTHREADS))
 #          define REPLACE_MALLOC
 #      else
 #          undef SBRK_OK
diff -Naur 3.3/src/string_spec 3.3sqlite/src/string_spec
--- 3.3/src/string_spec	2005-11-08 08:31:45.000000000 +0100
+++ 3.3sqlite/src/string_spec	2005-12-06 00:05:58.000000000 +0100
@@ -229,5 +229,8 @@
 SUCCESS         "success"
 
 #endif
+#ifdef USE_SQLITE3
+SQLITE_OPEN	"sl_open"
+#endif
 
 /***************************************************************************/
diff -Naur 3.3/src/xalloc.c 3.3sqlite/src/xalloc.c
--- 3.3/src/xalloc.c	2005-11-25 08:19:27.000000000 +0100
+++ 3.3sqlite/src/xalloc.c	2005-12-06 00:12:03.000000000 +0100
@@ -329,6 +329,15 @@
 #    warning ""
 #endif
 
+#if defined(USE_SQLITE3) && defined(SQLITE3_USES_PTHREADS) && !defined(MEM_THREADSAFE) && !defined(MEM_MAIN_THREADSAFE)
+#    warning ""
+#    warning "-----------------------------------"
+#    warning "SQLite3 uses PThreads, but the allocator"
+#    warning "is not threadsafe!"
+#    warning "-----------------------------------"
+#    warning ""
+#endif
+
 #if defined(MALLOC_ptmalloc) && defined(GC_SUPPORT) && defined(__FreeBSD__)
 #    warning ""
 #    warning "-----------------------------------"
sqlite3_all.diff (30,401 bytes)   

Activities

dafire

2003-08-24 13:52

reporter   ~0000025

updated the patch

dafire

2003-08-31 07:53

reporter   ~0000026

updated again :)

dafire

2004-03-28 08:11

reporter   ~0000035

partly rewrote .. fixed a few bugs
last version was in the finalfrontier driver for about 6 month without causing troubles ;)

Gnomi

2005-11-11 20:46

manager   ~0000403

I ported Dafire's patch to SQLite 3 and uploaded the diff. I especially paid attention not to have memory leaks. There is a todo item though, which requires to call LPC functions from within a sqlite callback. I have to figure out, how to do this carefully.

Greetings,
Gnomi.

Gnomi

2005-11-23 13:50

manager   ~0000409

Uploaded documentation for the efuns (documentation for sl_exec is specific to the SQLite3 version).

Gnomi

2005-11-28 14:05

manager   ~0000429

When SQLite3 is compiled as threadsafe it uses Pthreads and therefore LDMud should not replace malloc (SBRK_OK should be undef'd in machine.h), also a threadsafe memory allocator should be used.

Gnomi

2005-12-05 18:25

manager   ~0000445

So, I made a new diff (sqlite3_all.diff) that contains both code and documentation and also has patches for configure.in (but I didn't run autoreconf before making the diff). The configure script now also checks whether libsqlite3 uses pthreads (and the memory allocators act accordingly).

lars

2005-12-05 19:26

reporter   ~0000446

I have implemented the SQLite-3 version now - is the older one still useful?

I leave it to Gnomi to implement the still-missing callback, as he has a better idea of what it needs to do.

Issue History

Date Modified Username Field Change
2003-08-14 15:13 dafire New Issue
2003-08-24 13:52 dafire Note Added: 0000025
2003-08-31 07:53 dafire Note Added: 0000026
2004-03-28 08:11 dafire Note Added: 0000035
2005-05-01 12:40 lars File Added: pkg_sqlite.diff
2005-05-01 12:41 lars File Added: sqlite.html
2005-11-11 20:37 Gnomi File Added: sqlite3.diff
2005-11-11 20:46 Gnomi Note Added: 0000403
2005-11-23 13:48 Gnomi File Added: sqlite3.doc.diff
2005-11-23 13:50 Gnomi Note Added: 0000409
2005-11-28 14:05 Gnomi Note Added: 0000429
2005-12-05 18:20 Gnomi File Added: sqlite3_all.diff
2005-12-05 18:25 Gnomi Note Added: 0000445
2005-12-05 19:26 lars Status new => resolved
2005-12-05 19:26 lars Fixed in Version => 3.3.713
2005-12-05 19:26 lars Resolution open => fixed
2005-12-05 19:26 lars Assigned To => lars
2005-12-05 19:26 lars Note Added: 0000446
2006-02-28 20:04 lars Status resolved => closed
2010-11-16 09:42 lars Source_changeset_attached => ldmud.git master 80d9e420
2018-01-29 18:59 lars Source_changeset_attached => ldmud.git master 80d9e420
2018-01-29 21:57 lars Source_changeset_attached => ldmud.git master 80d9e420