]> git.mjollnir.org Git - s9y.git/commitdiff
Add sqlite3 support, by geekmug
authorgarvinhicking <garvinhicking>
Fri, 18 May 2007 07:59:14 +0000 (07:59 +0000)
committergarvinhicking <garvinhicking>
Fri, 18 May 2007 07:59:14 +0000 (07:59 +0000)
docs/NEWS
include/admin/category.inc.php
include/db/db.inc.php
include/db/sqlite3.inc.php [new file with mode: 0644]
include/functions_config.inc.php
include/functions_entries.inc.php
include/functions_installer.inc.php
include/functions_upgrader.inc.php

index e90bfea0b7b869b2ffa9e6dbbdfa5125482f028b..d09ca2a8492d7065bf8faab6c862a8321134a15c 100644 (file)
--- a/docs/NEWS
+++ b/docs/NEWS
@@ -3,6 +3,9 @@
 Version 1.2 ()
 ------------------------------------------------------------------------
 
+    * Add support for sqlite3 (http://php-sqlite3.sourceforge.net/), by 
+      geekmug
+
     * Change database types for IP addresses to varchar(64) to support
       IPv6 (garvinhicking)
 
index e9c25a5b8837502dc0ddf2cfc017cfc74ca44443..5ed49b9f1fc21d4f97ab9e963b0d9db2393da4e6 100644 (file)
@@ -73,7 +73,7 @@ if ($serendipity['GET']['adminAction'] == 'doDelete' && serendipity_checkFormTok
         $remaining_cat = (int)$serendipity['POST']['cat']['remaining_catid'];
         $category_ranges = serendipity_fetchCategoryRange((int)$serendipity['GET']['cid']);
         $category_range  = implode(' AND ', $category_ranges);
-        if ($serendipity['dbType'] == 'postgres' || $serendipity['dbType'] == 'sqlite') {
+        if ($serendipity['dbType'] == 'postgres' || $serendipity['dbType'] == 'sqlite' || $serendipity['dbType'] == 'sqlite3') {
             $query = "UPDATE {$serendipity['dbPrefix']}entrycat
                         SET categoryid={$remaining_cat} WHERE entryid IN
                         (
index afa87919a8290b89972aa6a5704c5f865e288ce2..91765e3a29b0f41a7ae211fb08d90ae3d29efc52 100644 (file)
@@ -123,6 +123,7 @@ function serendipity_db_get_interval($val, $ival = 900) {
 
     switch($serendipity['dbType']) {
         case 'sqlite':
+        case 'sqlite3':
             $interval = $ival;
             $ts       = time();
             break;
diff --git a/include/db/sqlite3.inc.php b/include/db/sqlite3.inc.php
new file mode 100644 (file)
index 0000000..934e1f0
--- /dev/null
@@ -0,0 +1,395 @@
+<?php # $Id: sqlite.inc.php 1670 2007-04-10 13:23:34Z garvinhicking $
+# Copyright (c) 2003-2005, Jannis Hermanns (on behalf the Serendipity Developer Team)
+# All rights reserved.  See LICENSE file for licensing details
+
+// SQLite3 only fetches by assoc, we will emulate the other result types
+define(SQLITE3_ASSOC, 0);
+define(SQLITE3_NUM, 1);
+define(SQLITE3_BOTH, 2);
+
+if (!function_exists('sqlite3_open')) {
+    @dl('sqlite.so');
+    @dl('sqlite.dll');
+}
+
+/**
+ * Tells the DB Layer to start a DB transaction.
+ *
+ * @access public
+ */
+function serendipity_db_begin_transaction(){
+    serendipity_db_query('begin transaction');
+}
+
+/**
+ * Tells the DB Layer to end a DB transaction.
+ *
+ * @access public
+ * @param  boolean  If true, perform the query. If false, rollback.
+ */
+function serendipity_db_end_transaction($commit){
+    if ($commit){
+        serendipity_db_query('commit transaction');
+    }else{
+        serendipity_db_query('rollback transaction');
+    }
+}
+
+/**
+ * Connect to the configured Database
+ *
+ * @access public
+ * @return  ressource   connection handle
+ */
+function serendipity_db_connect()
+{
+    global $serendipity;
+
+    if (isset($serendipity['dbConn'])) {
+        return $serendipity['dbConn'];
+    }
+
+       // SQLite3 doesn't support persistent connections
+    $serendipity['dbConn'] = sqlite3_open($serendipity['serendipityPath'] . $serendipity['dbName'] . '.db');
+
+    return $serendipity['dbConn'];
+}
+
+function serendipity_db_reconnect() {
+}
+
+/**
+ * Returns a escaped string, so that it can be safely included in a SQL string encapsulated within quotes, without allowing SQL injection.
+ *
+ * @access  public
+ * @param   string   input string
+ * @return  string   output string
+ */
+function serendipity_db_escape_string($string)
+{
+    static $search  = array("\x00", '%',   "'",   '\"');
+    static $replace = array('%00',  '%25', "''", '\\\"');
+
+    return str_replace($search, $replace, $string);
+}
+
+/**
+ * Returns the number of affected rows of a SQL query
+ *
+ * @access public
+ * @return int      Number of affected rows
+ */
+function serendipity_db_affected_rows()
+{
+    global $serendipity;
+
+    return sqlite3_changes($serendipity['dbConn']);
+}
+
+/**
+ * Returns the number of updated rows in a SQL query
+ *
+ * @access public
+ * @return int  Number of updated rows
+ */
+function serendipity_db_updated_rows()
+{
+    global $serendipity;
+    // It is unknown whether sqllite returns rows MATCHED or rows UPDATED
+    return sqlite3_changes($serendipity['dbConn']);
+}
+
+/**
+ * Returns the number of matched rows in a SQL query
+ *
+ * @access public
+ * @return int  Number of matched rows
+ */
+function serendipity_db_matched_rows()
+{
+    global $serendipity;
+    // It is unknown whether sqllite returns rows MATCHED or rows UPDATED
+    return sqlite3_changes($serendipity['dbConn']);
+}
+
+/**
+ * Returns the latest INSERT_ID of an SQL INSERT INTO command, for auto-increment columns
+ *
+ * @access public
+ * @return int      Value of the auto-increment column
+ */
+function serendipity_db_insert_id()
+{
+    global $serendipity;
+
+    return sqlite3_last_insert_rowid($serendipity['dbConn']);
+}
+
+/**
+ * Parse result arrays into expected format for further operations
+ *
+ * SQLite does not support to return "e.entryid" within a $row['entryid'] return.
+ * So this function manually iteratse through all result rows and rewrites 'X.yyyy' to 'yyyy'.
+ * Yeah. This sucks. Don't tell me!
+ *
+ * @access private
+ * @param  ressource    The row ressource handle
+ * @param  int          Bitmask to tell whether to fetch numerical/associative arrays
+ * @return array        Propper array containing the ressource results
+ */
+function serendipity_db_sqlite_fetch_array($res, $type = SQLITE3_BOTH)
+{
+    static $search  = array('%00',  '%25');
+    static $replace = array("\x00", '%');
+
+    $row = sqlite3_fetch_array($res);
+    if (!is_array($row)) {
+        return $row;
+    }
+
+    /* strip any slashes, correct fieldname */
+    foreach ($row as $i => $v) {
+        // TODO: If a query of the format 'SELECT a.id, b.text FROM table' is used,
+        //       the sqlite extension will give us key indizes 'a.id' and 'b.text'
+        //       instead of just 'id' and 'text' like in mysql/postgresql extension.
+        //       To fix that, we use a preg-regex; but that is quite performance costy.
+        //       Either we always need to use 'SELECT a.id AS id, b.text AS text' in query,
+        //       or the sqlite extension may get fixed. :-)
+        $row[preg_replace('@^.+\.(.*)@', '\1', $i)] = str_replace($search, $replace, $v);
+    }
+
+    if ($type == SQLITE3_NUM)
+        $frow = array();
+    else
+        $frow = $row;
+
+    if ($type != SQLITE3_ASSOC) {
+        $i = 0;
+        foreach($row as $k => $v) {
+            $frow[$i] = $v;
+            $i++;
+        }
+    }
+
+    return $frow;
+}
+
+/**
+ * Assemble and return SQL condition for a "IN (...)" clause
+ *
+ * @access public
+ * @param  string   table column name
+ * @param  array    referenced array of values to search for in the "IN (...)" clause
+ * @param  string   condition of how to associate the different input values of the $search_ids parameter
+ * @return string   resulting SQL string
+ */
+function serendipity_db_in_sql($col, &$search_ids, $type = ' OR ') {
+    $sql = array();
+    if (!is_array($search_ids)) {
+        return false;
+    }
+
+    foreach($search_ids AS $id) {
+        $sql[] = $col . ' = ' . $id;
+    }
+
+    $cond = '(' . implode($type, $sql) . ')';
+    return $cond;
+}
+
+/**
+ * Perform a DB Layer SQL query.
+ *
+ * This function returns values dependin on the input parameters and the result of the query.
+ * It can return:
+ *   false if there was an error,
+ *   true if the query succeeded but did not generate any rows
+ *   array of field values if it returned a single row and $single is true
+ *   array of array of field values if it returned row(s) [stacked array]
+ *
+ * @access public
+ * @param   string      SQL query to execute
+ * @param   boolean     Toggle whether the expected result is a single row (TRUE) or multiple rows (FALSE). This affects whether the returned array is 1 or 2 dimensional!
+ * @param   string      Result type of the array indexing. Can be one of "assoc" (associative), "num" (numerical), "both" (numerical and associative, default)
+ * @param   boolean     If true, errors will be reported. If false, errors will be ignored.
+ * @param   string      A possible array key name, so that you can control the multi-dimensional mapping of an array by the key column
+ * @param   string      A possible array field name, so that you can control the multi-dimensional mapping of an array by the key column and the field value.
+ * @param   boolean     If true, the executed SQL error is known to fail, and should be disregarded (errors can be ignroed on DUPLICATE INDEX queries and the likes)
+ * @return  mixed       Returns the result of the SQL query, depending on the input parameters
+ */
+function &serendipity_db_query($sql, $single = false, $result_type = "both", $reportErr = true, $assocKey = false, $assocVal = false, $expectError = false)
+{
+    global $serendipity;
+    static $type_map = array(
+                         'assoc' => SQLITE3_ASSOC,
+                         'num'   => SQLITE3_NUM,
+                         'both'  => SQLITE3_BOTH,
+                         'true'  => true,
+                         'false' => false
+    );
+
+    static $debug = false;
+
+    if ($debug) {
+        // Open file and write directly. In case of crashes, the pointer needs to be killed.
+        $fp = @fopen('sqlite.log', 'a');
+        fwrite($fp, '[' . date('d.m.Y H:i') . '] SQLITE QUERY: ' . $sql . "\n\n");
+        fclose($fp);
+    }
+
+    if ($reportErr && !$expectError) {
+        $res = sqlite3_query($serendipity['dbConn'], $sql);
+    } else {
+        $res = @sqlite3_query($serendipity['dbConn'], $sql);
+    }
+
+    if (!$res) {
+        if (!$expectError && !$serendipity['production']) {
+            var_dump($res);
+            var_dump($sql);
+            $msg = "problem with query";
+            return $msg;
+        }
+        if ($debug) {
+            $fp = @fopen('sqlite.log', 'a');
+            fwrite($fp, '[' . date('d.m.Y H:i') . '] [ERROR] ' . "\n\n");
+            fclose($fp);
+        }
+
+        return $type_map['false'];
+    }
+
+    if ($res === true) {
+        return $type_map['true'];
+    }
+
+    $rows = array();
+
+    while (($row = serendipity_db_sqlite_fetch_array($res, $type_map[$result_type]))) {
+        if (!empty($assocKey)) {
+            // You can fetch a key-associated array via the two function parameters assocKey and assocVal
+            if (empty($assocVal)) {
+                $rows[$row[$assocKey]] = $row;
+            } else {
+                $rows[$row[$assocKey]] = $row[$assocVal];
+            }
+        } else {
+            $rows[] = $row;
+        }
+    }
+
+    if ($debug) {
+        $fp = @fopen('sqlite.log', 'a');
+        fwrite($fp, '[' . date('d.m.Y H:i') . '] SQLITE RESULT: ' . print_r($rows, true). "\n\n");
+        fclose($fp);
+    }
+
+    if ($single && count($rows) == 1) {
+        return $rows[0];
+    }
+
+    if (count($rows) == 0) {
+        if ($single)
+            return $type_map['false'];
+        return $type_map['true'];
+    }
+    
+    return $rows;
+}
+
+/**
+ * Try to connect to the configured Database (during installation)
+ *
+ * @access public
+ * @param  array     input configuration array, holding the connection info
+ * @param  array     referenced array which holds the errors that might be encountered
+ * @return boolean   return true on success, false on error
+ */
+function serendipity_db_probe($hash, &$errs)
+{
+    global $serendipity;
+
+    $dbName = (isset($hash['sqlitedbName']) ? $hash['sqlitedbName'] : $hash['dbName']);
+
+    if (!function_exists('sqlite3_open')) {
+        $errs[] = 'SQLite extension not installed. Run "pear install sqlite" on your webserver or contact your systems administrator regarding this problem.';
+        return false;
+    }
+
+    if (defined('S9Y_DATA_PATH')) {
+        // Shared installations!
+        $dbfile = S9Y_DATA_PATH . $dbName . '.db';
+    } else {
+        $dbfile = $serendipity['serendipityPath'] . $dbName . '.db';
+    }
+
+    $serendipity['dbConn'] = sqlite3_open($dbfile);
+
+    if ($serendipity['dbConn']) {
+        return true;
+    }
+
+    $errs[] = "Unable to open \"$dbfile\" - check permissions (directory needs to be writeable for webserver)!";
+    return false;
+}
+
+/**
+ * Prepares a Serendipty query input to fully valid SQL. Replaces certain "template" variables.
+ *
+ * @access public
+ * @param  string   SQL query with template variables to convert
+ * @return ressource    SQL ressource handle of the executed query
+ */
+function serendipity_db_schema_import($query)
+{
+    static $search  = array('{AUTOINCREMENT}', '{PRIMARY}', '{UNSIGNED}', '{FULLTEXT}', '{BOOLEAN}', '{UTF_8}');
+    static $replace = array('INTEGER', 'PRIMARY KEY', '', '', 'BOOLEAN NOT NULL', '');
+
+    if (stristr($query, '{FULLTEXT_MYSQL}')) {
+        return true;
+    }
+
+    $query = trim(str_replace($search, $replace, $query));
+    if ($query{0} == '@') {
+        // Errors are expected to happen (like duplicate index creation)
+        return serendipity_db_query(substr($query, 1), false, 'both', false, false, false, true);
+    } else {
+        return serendipity_db_query($query);
+    }
+}
+
+/**
+ * Returns the option to a LIMIT SQL statement, because it varies accross DB systems
+ *
+ * @access public
+ * @param  int      Number of the first row to return data from
+ * @param  int      Number of rows to return
+ * @return string   SQL string to pass to a LIMIT statement
+ */
+function serendipity_db_limit($start, $offset) {
+    return $start . ', ' . $offset;
+}
+
+/**
+ * Return a LIMIT SQL option to the DB Layer as a full LIMIT statement
+ *
+ * @access public
+ * @param   SQL string of a LIMIT option
+ * @return  SQL string containing a full LIMIT statement
+ */
+function serendipity_db_limit_sql($limitstring) {
+    return ' LIMIT ' . $limitstring;
+}
+
+/**
+ * Returns the SQL code used for concatenating strings
+ *
+ * @access public
+ * @param  string   Input string/column to concatenate
+ * @return string   SQL parameter
+ */
+function serendipity_db_concat($string) {
+    return 'concat(' . $string . ')';
+}
+
+/* vim: set sts=4 ts=4 expandtab : */
index abbd5584d0bf92287bb053f8e6156f980b00ca0c..03972156e4b7fa7d1645c64c13bc2d10f723cbd8 100644 (file)
@@ -784,6 +784,9 @@ function serendipity_probeInstallation($item) {
             if (extension_loaded('sqlite')) {
                 $res['sqlite'] = 'SQLite';
             }
+            if (extension_loaded('SQLITE3')) {
+                $res['sqlite3'] = 'SQLite3';
+            }
             break;
 
         case 'rewrite' :
index e1ccb9c9bcea0ca87017f3c7ca67b8c815c41c8c..f5d350e22df89c6155a18a816f557a4bcc81c924 100644 (file)
@@ -722,7 +722,7 @@ function &serendipity_searchEntries($term, $limit = '') {
         $group     = '';
         $distinct  = 'DISTINCT';
         $cond['find_part'] = "(title ILIKE '%$term%' OR body ILIKE '%$term%' OR extended ILIKE '%$term%')";
-    } elseif ($serendipity['dbType'] == 'sqlite') {
+    } elseif ($serendipity['dbType'] == 'sqlite' || $serendipity['dbType'] == 'sqlite3') {
         // Very extensive SQLite search. There currently seems no other way to perform fulltext search in SQLite
         // But it's better than no search at all :-D
         $group     = 'GROUP BY e.id';
@@ -846,7 +846,7 @@ function serendipity_getTotalEntries() {
     global $serendipity;
 
     // The unique query condition was built previously in serendipity_fetchEntries()
-    if ($serendipity['dbType'] == 'sqlite') {
+    if ($serendipity['dbType'] == 'sqlite' || $serendipity['dbType'] == 'sqlite3') {
         $querystring  = "SELECT count(e.id) {$serendipity['fullCountQuery']} GROUP BY e.id";
     } else {
         $querystring  = "SELECT count(distinct e.id) {$serendipity['fullCountQuery']}";
@@ -855,7 +855,7 @@ function serendipity_getTotalEntries() {
     $query =& serendipity_db_query($querystring);
 
     if (is_array($query) && isset($query[0])) {
-        if ($serendipity['dbType'] == 'sqlite') {
+        if ($serendipity['dbType'] == 'sqlite' || $serendipity['dbType'] == 'sqlite3') {
             return count($query);
         } else {
             return $query[0][0];
index 897c34583757bf5271ade53954164a1c549ab94a..5844afefd1d0848db19c0f4a2aca61251a1044bb 100644 (file)
@@ -727,7 +727,7 @@ function serendipity_checkInstallation() {
         $errs[] = sprintf(CANT_EXECUTE_BINARY, 'convert imagemagick');
     }
 
-    if ($_POST['dbType'] == 'sqlite') {
+    if ($_POST['dbType'] == 'sqlite' || $_POST['dbType'] == 'sqlite3') {
         // We don't want that our SQLite db file can be guessed from other applications on a server
         // and have access to our's. So we randomize the SQLite dbname.
         $_POST['sqlitedbName'] = $_POST['dbName'] . '_' . md5(time());
index 34def66e52296e47f88354dc5df8b74c0309a63c..e9592610890fea01d3a725dd6615134347a41b45 100644 (file)
@@ -48,6 +48,7 @@ $obsolete_files = array(
     'serendipity_db_postgres.inc.php',
     'serendipity_db_pdo-postgres.inc.php',
     'serendipity_db_sqlite.inc.php',
+    'serendipity_db_sqlite3.inc.php',
     'htaccess.cgi.errordocs.tpl',
     'htaccess.cgi.normal.tpl',
     'htaccess.cgi.rewrite.tpl',