Warning!

It seems that you are using an anti-advertisement software like AdBlock.
I like AdBlock too, but I configured it to block only invasive and annoying advertisement and popups.

CoolSoft can exists thanks to a few banners and no popups.
Please add this site it to your exclusion list, as shown in the following image.

Thanks for your help.

Drupal-SQLite

Introduction

This page describes Drupal-SQLite, my attempt to make Drupal 6 work with a SQLite database.

SQLite is a lightweight, fast, public domain, easily integrable, multiplatform database system.
It's used by many of the greatest open source projects; just to name one... Mozilla Foudation on their Firefox & Thunderbird.

Why should you need this?
Well, most hosting providers gives you PHP 5.2+ for free, but they ask a few bucks for a MySQL database. If this could worth the case for mid-large sites, with hundreds or thousands users a day, it's a waste for mid-small sites (like mine).

With SQLite support you can setup a preconfigured Drupal site which works just out of the box.
Suppose you're a theme designer or a module developer: you can create a self-working Drupal installation with only 1,5 Mb overload.

My work started from here.
In this long post, some good guys put their efforts to have a SQLite database layer for Drupal 4.7, then 5 and finally 6. The thread is now closed because some of them moved to the forthcoming Drupal 7 series, which will have SQLite as first class citizen; while waiting for it, Drupal-SQLite gives you a full working SQLite database layer for Drupal 6.

Alternatives

There are other Drupal+SQLite bundles out there, but none fulfill my needs.

Speedtech.it

(link currently down)
Working (but old) Drupal 5.6 version, patched for SQLite.

Pros:

  • works great (this site used it till Oct 2008)

Cons:

  • it's a Drupal 5 version, no PDO then its SQLite support is limited to SQLite 2.x databases (which are not performing as 3.x ones)
  • no more updates, last version was against Drupal 5.6

Siren

Deep (maybe too deep) patch against Drupal 6.x

Pros:

  • PDO support, then 3.x SQLite databases support
  • more databases other than SQLite

Cons:

  • too deep changes to Drupal core files
    Read from it's official site: "According to the needs of PDO and Oracle drivers implementation, ALL core queries and some APIs are hacked for compatibility concern."
  • even if it's based on Drupal (ver. 6.4) now it's a complete fork; this means you can't use Drupal updates.

Drupal-SQLite

Drupal-SQLite comes in two flavours:
- a .zip archive ready to be unpacked in your web server root
- a .patch file to apply to a default Drupal 6 tree

After installing the one you prefer, just open index.php in your Drupal site and you're ready to start.

These are Drupal-SQLite pros:

  • built against Drupal 6.10 (and following, read next point)
  • no core files modified (except one: includes/install.inc.php) (*)
  • uses PDO layer (even if original Drupal 6 doesn't), so SQLite 3.x databases can be created
  • supports a growing list of modules

(*)  Drupal-SQLite patches this file to let the user choose SQLite as its database. After the first install, this file is not used anymore and can be safely overwritten. Other Drupal-SQLite related files are additional ones; saying this I mean you could install latest Drupal updates being sure you'll not broke Drupal-SQLite.

Requirements

Drupal-SQLite requires PHP5 with PDO-SQLite support enabled.
This is NOT the standard SQLite support (non PDO) and is provided through a different extension named php_pdo_sqlite.dll (win) or php_pdo_sqlite.so (linux).

To test if PDO_SQLite support is enabled, create a file named phpinfo.php containing:

<?php
phpinfo();
?>

Now open this file in your browser and check if a section named pdo_sqlite exists and is enabled.

NOTE to XAMPP users:
XAMPP 1.7.1 comes with pdo_sqlite disabled by default.

To enable it:

  • Stop all XAMPP services
  • open xampp\php\php.ini file
  • find the rows containing the following strings:
    • row 646: extension=php_pdo_sqlite.dll
    • row 662: extension=php_sqlite.dll
  • remove the leading ; to enable PDO-SQLite
  • restart the XAMPP services

How to install

Depending on your hosting solution, choose the file to download:

  • Full archive
    This should be the best solution for Windows based hosting, but it surely works on Linux too.
    Download the archive and extract it in your web server root folder.
     
  • Patch file
    Since applying patches on Windows is not so easy, I suggest this to Linux users only.
    Download patch file of the original version you're going to patch and apply it to Drupal tree you already extracted to your web server root folder.
    If the patch applied successfully then go on.

Now open install.php file and follow the instructions; don't forget to:

  • choose the Drupal-SQLite profile at the very first page to have an optimized configuration
  • select sqlite as database type inside the "basic options" block (I can't find a way to force this selection through the profile)

Security notes

You should protect your database file, which is by default sites/default/*.s3db, from being downloaded.
Drupal-SQLite comes with a preconfigured .htaccess files that denies access to *.s3db files.
Please edit it if you changed proposed database file name, then test if it works.

Core modules

Drupal-SQLite comes with a profile which, by default, disables some core modules to make it run faster.
Time-consuming modules, like dblog and syslog, are disabled by default.
Enabled modules are: 'color', 'comment', 'help', 'menu' and 'taxonomy'.

"sqlitetools" module

Since your database is a flat-file, making a backup is now easy as copying the file itself.
I created a specific module, named sqlitetool (you can find it in download area) to accomplish this task; backups are stored into/retrieved from ZIP files.
The same module allowsto cleanup the active database (VACUUM) to free unused space.

Adding external modules

Drupal-SQLite is a non-invasive patch against Drupal and should work with each module accessing the database through the Drupal DB subsystem.
Sometimes module developers need to use DB specific SQL queries, and they put a switch statement in their code, like this (from xmlsitemap module):

switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      $query .= "LEFT JOIN {url_alias} ua ON ua.src = ('node/' || '%d')";
      break;
    case 'pgsql':
      $query .= "LEFT JOIN {url_alias} ua ON ua.src = CONCAT('node/', CAST(%d AS VARCHAR))";
      break;
}

As you can see, the query is composed according to the active db and, worst of all, there's no 'default:' item at the end of switch.
Now we have: $GLOBALS['db_type'] == 'sqlite', then no code is executed and no query (or part of it) is composed.

In this case the fix is quite simple:

switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
    case 'sqlite':
      $query .= "LEFT JOIN {url_alias} ua ON ua.src = ('node/' || '%d')";
      break;
    case 'pgsql':
      $query .= "LEFT JOIN {url_alias} ua ON ua.src = CONCAT('node/', CAST(%d AS VARCHAR))";
      break;
}

Note that SQLite shares the same code as MySQL.

So my suggestion is: before installing a new module, do a find (grep for Linux friends) inside module folders and look for mysql or pgsql.
If you find it, examine the code and try to find a way to accomodate; if you can't, drop a line to module developers and ask them to fix it for you.
Ok ok, I know that SQLite is not officially supported, but in most of the cases I saw the fix is just one line, like this.

Known working modules

I tried these modules (most of them are used here) and I can confirm they work untouched.
Please let me know if you used a not-listed module (and it worked).

Module name Version Note
admin_menu 6.x-1.3  
blockquote 6.x-1.0  
captcha 6.x-1.0  
cck 6.4-2.4  
comment_notify 6.x-1.2  
devel 6.x-1.17 (see this comment)
dhtml_menu 6.x-3.4  
fckeditor 6.x-2.0-alpha5  
geshifilter 6.x-1.2  
languageicons 6.x-1.1  
pathauto 6.x-2.x-dev  
permalink 6.x-1.1  
poormanscron 6.x-1.0  
potx (Translation Template Extractor) 6.x-3.0  
service_links 6.x-1.0  
taxonomy_dhtml 6.x-1.0-rc3  
token 6.x-1.11  
wysiwyg 6.x-2.0 + FCKeditor 2.6.4.1

Known not-working modules

These modules do not work with Drupal-SQLite out-of-the-box and a patch is required.
This patch could concern few lines (relevance=1) or require the whole module to be patched (relevance=5).

Module name Version Relevance
date 6.x-2.3  5

Acknowledgements

Changelog

See here.

Download

You can download files here.

Get Drupal-SQLite at SourceForge.net. Fast, secure and Free Open Source software downloads

Comments

Initial "Configure site" not working

Certain changes made in the initital "Configure site" page after the Drupal-SQLite installation are not being saved, and I have to go back to the admin pages to make those changes again. The fields that apparently aren't saving include:
  • Site name
  • Administrator account: user name
  • Administrator account: email address
I had to log back in using the user name "Administrator" even though I changed that field during installation. The db is writeable, as I'm able to use the site after installation. I'm using the Entropy package of PHP, which uses PHP 5.2.9 and SQLite database 3.3.7 according to Drupal's status report.

Confirm

I can confirm this bug. Very frustrating till you figure out to try 'Administrator' name. Password recovery also doesn't work because of e-mail not set.

Thanks for the feedback

Thanks for the detailed feedback, I'll give a look ASAP.

Calendar issues

Hi, I'm trying to set up a calendar style view on drupal-sqlite but always get an error related to a wrong query. Once I setup the view, the list shows the following error:
  • warning: PDO::prepare() [pdo.prepare]: SQLSTATE[HY000]: General error: 1 near "<=": syntax error in C:optApache2htdocsdrupal-sqliteincludesdatabase.sqlite.inc on line 195.

  • user warning: near "<=": syntax error
    query: SELECT node.nid AS nid, node.title AS node_title, node_data_field_date.field_date_value AS node_data_field_date_field_date_value, node_data_field_date.field_date_value2 AS node_data_field_date_field_date_value2, node_data_field_date.field_date_rrule AS node_data_field_date_field_date_rrule, node_data_field_date.delta AS node_data_field_date_delta, node.type AS node_type, node.vid AS node_vid FROM node node LEFT JOIN content_field_date node_data_field_date ON node.vid = node_data_field_date.vid WHERE ( <= '2009-08' AND >= '2009-08') in C:optApache2htdocsdrupal-sqlitemodulesviews-6.x.3.x-devviewspluginsviews_plugin_query_default.inc on line 1094.

As you can see, the column that should have been passed on as argument is ommitted! WHERE ( <= '2009-08' AND >= '2009-08'). As I've have not found this issue in any other drupal related websites I supposed it is related to your patch. Am I right? I'm using the following versions:
- Windows XP
- SQLite3
- Drupal-SQLite 6.13-1.3
  -> views-6.x.3.x-dev
  -> calendar-6.x.2.2
  -> cck-6.x.2.5
  -> date-6.x.2.3

Bad news

Hi Davyd, I have bad news for you.
As I said, not all of Drupal modules will work, and Date is one of them.

I setup an environment like yours and I see that Date module is not SQLite aware at all.
A quich search for 'mysql' string returned a bunch of results from the Date module.
File date/date_api_sql.inc contains a lot of switch constructs due to the fact it is strictly DB-related.

Example, at line 10:

function date_sql_concat($array) {
  global $db_type;
  switch ($db_type) {
    case('mysql'):
    case('mysqli'):
      return "CONCAT(". implode(",", $array) .")";
    case('pgsql'):
      return implode(" || ", $array);
  }
}

This code is easily patchable to make it work with SQLite:

function date_sql_concat($array) {
  global $db_type;
  switch ($db_type) {
    case('mysql'):
    case('mysqli'):
      return "CONCAT(". implode(",", $array) .")";
    case('sqlite'):
    case('pgsql'):
      return implode(" || ", $array);
  }
}

This is the easiest one, other functions are harder.
See sql_field() at line 163, which requires deep changes and, maybe, missing SQLite SQL functions to be added.

I think that making Date module work with Drupal-SQLite is not feasible.
Sorry.

Patch file for date_api_sql.inc

Hi Davyd, I had the same problem two months ago on my site. As Claudio already said, the Date module needs a lot of patches. In almost every function you have a switch ($db_type) { Here my patch file for date/date_api_sql.inc. It is by far not perfect, but it works for me, may be also for you.
--- date_api_sql.orig.inc	So Mai  3 17:37:16 2009
+++ date_api_sql.inc	Di Jul 14 20:58:37 2009
@@ -14,6 +14,7 @@
     case('mysqli'):
       return "CONCAT(". implode(",", $array) .")";
     case('pgsql'):
+    case('sqlite'):
       return implode(" || ", $array);
   }
 }
@@ -30,6 +31,7 @@
     case('mysql'):
     case('mysqli'):
     case('pgsql'):
+    case('sqlite'):
       return "COALESCE(". implode(',', $array) .")";
   }  
 }
@@ -97,7 +99,10 @@
           if ($test == '2008-02-15 06:00:00') {
             $has_support = TRUE;
           }
-        break;
+          break;
+        case('sqlite'):
+          // no support
+          break;
       }
       variable_set('date_db_tz_support', $has_support);
     }
@@ -130,6 +135,9 @@
       elseif ($type == 'pgsql') {
         db_query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
       }
+      elseif ($type == 'sqlite') {
+        // no support
+      }
       $already_set = true;
     }
   }
@@ -185,6 +193,18 @@
             break;
         }
         break;
+      case('sqlite'):
+        switch ($this->date_type) {
+          case DATE_UNIX:
+            $field = "FROM_UNIXTIME($field)";
+            break;
+          case DATE_ISO:
+            $field = "REPLACE($field, 'T', ' ')";
+            break;
+          case DATE_DATETIME:
+            break;
+        }
+        break;
       case 'pgsql':
         switch ($this->date_type) {
           case DATE_UNIX:
@@ -216,6 +236,17 @@
           else {
             return "DATE_ADD($field, INTERVAL $offset SECOND)";
           }
+        case('sqlite'):
+          $offset = ($offset >= 0) ? "+ $offset" : ("- " . -$offset);
+          switch ($this->date_type) {
+            case DATE_UNIX:
+              return "($field $offset)";
+            case DATE_ISO:
+              return "STRFTIME('%Y-%m-%%dT%H:%M:%S', $field, '$offset SECONDS')";
+            case DATE_DATETIME:
+              return "DATETIME($field, '$offset SECONDS')";
+          }
+          break;
         case 'pgsql':
           return "($field + INTERVAL '$offset SECONDS')";;
       }
@@ -247,6 +278,16 @@
           case 'SUB':
             return "DATE_SUB($field, INTERVAL $count $granularity)";
           }
+      case('sqlite'):
+        $direction = ($direction == 'ADD') ? '+' : '-';
+        switch ($this->date_type) {
+          case DATE_UNIX:
+            return "STRFTIME('s', $field, '$direction $count $granularity')";
+          case DATE_ISO:
+            return "STRFTIME('%Y-%m-%%dT%H:%M:%S', $field, '$direction $count $granularity')";
+          case DATE_DATETIME:
+            return "DATETIME($field, '$direction $count $granularity')";
+        }
 
       case 'pgsql':
         $granularity .= 'S';
@@ -307,6 +348,8 @@
           // WITH TIME ZONE assumes the date is using the system
           // timezone, which should have been set to UTC.
           return "TIMESTAMP WITH TIME ZONE $field AT TIME ZONE $localzone";
+        case 'sqlite':
+          // no support
       }
     }
   }
@@ -336,6 +379,18 @@
           );
         $format = strtr($format, $replace);
         return "DATE_FORMAT($field, '$format')";
+      case('sqlite'):
+        $replace = array(
+          'Y' => '%Y', 'y' => '%y',
+          'm' => '%m', 'n' => '%c',
+          'd' => '%%d', 'j' => '%j',
+          'H' => '%H',
+          'i' => '%M',
+          's' => '%S',
+          'WW' => '%W',
+          );
+        $format = strtr($format, $replace);
+        return "STRFTIME('$format', $field)";
       case 'pgsql':
         $replace = array(
           'Y' => 'YYYY', 'y' => 'Y',
@@ -387,6 +442,7 @@
           // WEEK using arg 3 in mysql should return the same value as postgres EXTRACT
           return "WEEK($field, 3)";
         case('pgsql'):
+        case('sqlite'):
           return "EXTRACT(WEEK FROM($field))";
       }
     case('DOW'):
@@ -397,6 +453,7 @@
           // php date functions and postgres use 0 for Sunday and 6 for Saturday
           return "INTEGER(DAYOFWEEK($field) - 1)";
         case('pgsql'):
+        case('sqlite'):
           return "EXTRACT(DOW FROM($field))";
       }
     case('DOY'):
@@ -405,6 +462,7 @@
         case('mysqli'):
           return "DAYOFYEAR($field)";
         case('pgsql'):
+        case('sqlite'):
           return "EXTRACT(DOY FROM($field))";
       }
     }

Thanks

Thanks Dmitri for your patch and for all the other valuable ones you sent me before (see changelog).
A new forum will start soon: this way searching for issues and patches will be easier.

Devel module support

Hi!

I am really glad that you've done this port of drupal. It really works well, even with modules other than listed here. So far I've only had one problem with the devel module. It fails with an SQL error (on the devel_query table) upon install.

I have tried devel-6.x-1.17 and it will probably be the same with later versions as well. It is only the devel / devel module that's affected.
The fix is simple though: just open up the devel.install file from the module's directory, and change in the devel_schema() function this:

'primary key' => array('qid'), 
'indexes' => array('hash' => array('hash'))

Easy, not? ;)

When you uninstall the devel module - it might still say errors about database table being locked. Do not worry, if all else fails, and you really want to get rid of the devel tables, just open up the database from your favorite editor and droip the devel_* tables.

Thanks

Thanks for your tip and effort providing a workaround...

Still a need for page caching?

I've just set up this version of Drupal SQLite v6.12 on very low-memory (360MB) machine running nginx+fastcgi.  Very noticeable increase in page loads.

Is there still a performance benefit from page caching with the SQLite database layer?  Since cached content is stored in the database, caching would presumably cause the database flat file to grow in size substantially, and possiblity negate the desired effect of the caching.