diff options
25 files changed, 837 insertions, 125 deletions
diff --git a/.gitignore b/.gitignore index 25a6352f8d..18f598cf67 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,6 @@ /phpBB/images/avatars/upload/* /phpBB/store/* /phpBB/vendor -/tests/phpbb_unit_tests.sqlite2 +/tests/phpbb_unit_tests.sqlite* /tests/test_config*.php /tests/tmp/* diff --git a/.travis.yml b/.travis.yml index 88c902cd4d..629388ff16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,5 +40,7 @@ matrix: env: DB=mariadb - php: 5.4 env: DB=postgres + - php: 5.4 + env: DB=sqlite3 allow_failures: - php: hhvm diff --git a/phpBB/develop/add_permissions.php b/phpBB/develop/add_permissions.php index 449d931507..688e228729 100644 --- a/phpBB/develop/add_permissions.php +++ b/phpBB/develop/add_permissions.php @@ -376,6 +376,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting) case 'mssql': case 'sqlite': + case 'sqlite3': $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); break; diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index 9ab8bd193f..d89de2cee3 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -70,6 +70,7 @@ foreach ($supported_dbms as $dbms) case 'mysql_41': case 'firebird': case 'sqlite': + case 'sqlite3': fwrite($fp, "# DO NOT EDIT THIS FILE, IT IS GENERATED\n"); fwrite($fp, "#\n"); fwrite($fp, "# To change the contents of this file, edit\n"); diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 01eeea6540..0b5d06c191 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -134,7 +134,8 @@ <li>MySQL 3.23 or above (MySQLi supported)</li> <li>MariaDB 5.1 or above</li> <li>PostgreSQL 8.3+</li> - <li>SQLite 2.8.2+ (SQLite 3 is not supported)</li> + <li>SQLite 2.8.2+</li> + <li>SQLite 3.6.15+</li> <li>Firebird 2.1+</li> <li>MS SQL Server 2000 or above (directly or via ODBC or the native adapter)</li> <li>Oracle</li> diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index d28ee5b067..51715141eb 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -101,6 +101,10 @@ class acp_database $extractor = new sqlite_extractor($format, $filename, $time, $download, $store); break; + case 'sqlite3': + $extractor = new sqlite3_extractor($format, $filename, $time, $download, $store); + break; + case 'postgres': $extractor = new postgres_extractor($format, $filename, $time, $download, $store); break; @@ -135,6 +139,7 @@ class acp_database switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $extractor->flush('DELETE FROM ' . $table_name . ";\n"); break; @@ -325,6 +330,7 @@ class acp_database case 'mysql4': case 'mysqli': case 'sqlite': + case 'sqlite3': while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false) { $db->sql_query($sql); @@ -1052,6 +1058,112 @@ class sqlite_extractor extends base_extractor /** * @package acp */ +class sqlite3_extractor extends base_extractor +{ + function write_start($prefix) + { + $sql_data = "--\n"; + $sql_data .= "-- phpBB Backup Script\n"; + $sql_data .= "-- Dump of tables for $prefix\n"; + $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; + $sql_data .= "--\n"; + $sql_data .= "BEGIN TRANSACTION;\n"; + $this->flush($sql_data); + } + + function write_table($table_name) + { + global $db; + $sql_data = '-- Table: ' . $table_name . "\n"; + $sql_data .= "DROP TABLE $table_name;\n"; + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'table' + AND name = '" . $db->sql_escape($table_name) . "' + ORDER BY name ASC;"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // Create Table + $sql_data .= $row['sql'] . ";\n"; + + $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');"); + + while ($row = $db->sql_fetchrow($result)) + { + if (strpos($row['name'], 'autoindex') !== false) + { + continue; + } + + $result2 = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($row['name']) . "');"); + + $fields = array(); + while ($row2 = $db->sql_fetchrow($result2)) + { + $fields[] = $row2['name']; + } + $db->sql_freeresult($result2); + + $sql_data .= 'CREATE ' . ($row['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $row['name'] . ' ON ' . $table_name . ' (' . implode(', ', $fields) . ");\n"; + } + $db->sql_freeresult($result); + + $this->flush($sql_data . "\n"); + } + + function write_data($table_name) + { + global $db; + + $result = $db->sql_query("PRAGMA table_info('" . $db->sql_escape($table_name) . "');"); + + $col_types = array(); + while ($row = $db->sql_fetchrow($result)) + { + $col_types[$row['name']] = $row['type']; + } + $db->sql_freeresult($result); + + $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES ('; + + $sql = "SELECT * + FROM $table_name"; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + foreach ($row as $column_name => $column_data) + { + if (is_null($column_data)) + { + $row[$column_name] = 'NULL'; + } + else if ($column_data === '') + { + $row[$column_name] = "''"; + } + else if (stripos($col_types[$column_name], 'text') !== false || stripos($col_types[$column_name], 'char') !== false || stripos($col_types[$column_name], 'blob') !== false) + { + $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data)); + } + } + $this->flush($sql_insert . implode(', ', $row) . ");\n"); + } + } + + function write_end() + { + $this->flush("COMMIT;\n"); + parent::write_end(); + } +} + +/** +* @package acp +*/ class postgres_extractor extends base_extractor { function write_start($prefix) diff --git a/phpBB/includes/acp/acp_icons.php b/phpBB/includes/acp/acp_icons.php index 9c7acf506c..e4221a86dc 100644 --- a/phpBB/includes/acp/acp_icons.php +++ b/phpBB/includes/acp/acp_icons.php @@ -538,6 +538,7 @@ class acp_icons switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . $table); break; diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index 4512905539..9c1613e24a 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -271,6 +271,7 @@ class acp_main switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); break; @@ -376,6 +377,7 @@ class acp_main switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query("DELETE FROM $table"); break; diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index b42b852fba..8940410d72 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -114,6 +114,7 @@ class acp_profile switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' @@ -1204,7 +1205,8 @@ class acp_profile break; case 'sqlite': - if (version_compare(sqlite_libversion(), '3.0') == -1) + case 'sqlite3': + if (version_compare($db->sql_server_info(true), '3.0') == -1) { $sql = "SELECT sql FROM sqlite_master diff --git a/phpBB/includes/acp/acp_reasons.php b/phpBB/includes/acp/acp_reasons.php index 569bb73ab0..3f61a76d3a 100644 --- a/phpBB/includes/acp/acp_reasons.php +++ b/phpBB/includes/acp/acp_reasons.php @@ -253,6 +253,7 @@ class acp_reasons case 'oracle': case 'firebird': case 'sqlite': + case 'sqlite3': // Change the reports using this reason to 'other' $sql = 'UPDATE ' . REPORTS_TABLE . ' SET reason_id = ' . $other_reason_id . ", report_text = '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' || report_text diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 7b6345b9e3..786003a9ff 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3989,7 +3989,7 @@ function obtain_guest_count($item_id = 0, $item = 'forum') // Get number of online guests - if ($db->sql_layer === 'sqlite') + if ($db->sql_layer === 'sqlite' || $db->sql_layer === 'sqlite3') { $sql = 'SELECT COUNT(session_ip) as num_guests FROM ( diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 50b3b61eaa..db430c6940 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -2440,6 +2440,7 @@ function phpbb_cache_moderators($db, $cache, $auth) switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE); break; @@ -2907,6 +2908,7 @@ function get_database_size() break; case 'sqlite': + case 'sqlite3': global $dbhost; if (file_exists($dbhost)) diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php index 1646c79161..dbc66446b3 100644 --- a/phpBB/includes/functions_convert.php +++ b/phpBB/includes/functions_convert.php @@ -1650,6 +1650,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO) case 'mssql': case 'sqlite': + case 'sqlite3': case 'mssqlnative': $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); break; @@ -2037,6 +2038,7 @@ function update_topics_posted() switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); break; diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 4f8ec99d88..f484461b77 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -106,6 +106,15 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'AVAILABLE' => true, '2.0.x' => false, ), + 'sqlite3' => array( + 'LABEL' => 'SQLite3', + 'SCHEMA' => 'sqlite', + 'MODULE' => 'sqlite3', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\sqlite3', + 'AVAILABLE' => true, + '2.0.x' => false, + ), ); if ($dbms) @@ -206,14 +215,14 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, $db->sql_return_on_error(true); // Check that we actually have a database name before going any further..... - if ($dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite' && $dbms_details['DRIVER'] != 'phpbb\db\driver\oracle' && $dbname === '') + if ($dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite' && $dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite3' && $dbms_details['DRIVER'] != 'phpbb\db\driver\oracle' && $dbname === '') { $error[] = $lang['INST_ERR_DB_NO_NAME']; return false; } // Make sure we don't have a daft user who thinks having the SQLite database in the forum directory is a good idea - if ($dbms_details['DRIVER'] == 'phpbb\db\driver\sqlite' && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0) + if (($dbms_details['DRIVER'] == 'phpbb\db\driver\sqlite' || $dbms_details['DRIVER'] == 'phpbb\db\driver\sqlite3') && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0) { $error[] = $lang['INST_ERR_DB_FORUM_PATH']; return false; @@ -243,6 +252,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, break; case 'phpbb\db\driver\sqlite': + case 'phpbb\db\driver\sqlite3': $prefix_length = 200; break; @@ -299,6 +309,14 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } break; + case 'phpbb\db\driver\sqlite3': + $version = \SQLite3::version(); + if (version_compare($version['versionString'], '3.6.15', '<')) + { + $error[] = $lang['INST_ERR_DB_NO_SQLITE3']; + } + break; + case 'phpbb\db\driver\firebird': // check the version of FB, use some hackery if we can't get access to the server info if ($db->service_handle !== false && function_exists('ibase_server_info')) diff --git a/phpBB/install/convertors/functions_phpbb20.php b/phpBB/install/convertors/functions_phpbb20.php index f3b8c82131..b5a69abe93 100644 --- a/phpBB/install/convertors/functions_phpbb20.php +++ b/phpBB/install/convertors/functions_phpbb20.php @@ -1843,6 +1843,7 @@ function phpbb_create_userconv_table() break; case 'sqlite': + case 'sqlite3': $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' ( user_id INTEGER NOT NULL DEFAULT \'0\', username_clean varchar(255) NOT NULL DEFAULT \'\' diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php index 82311bd04d..13001426f7 100644 --- a/phpBB/install/install_convert.php +++ b/phpBB/install/install_convert.php @@ -249,6 +249,7 @@ class install_convert extends module switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $db->sql_query('DELETE FROM ' . SESSIONS_KEYS_TABLE); $db->sql_query('DELETE FROM ' . SESSIONS_TABLE); @@ -696,6 +697,7 @@ class install_convert extends module switch ($src_db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $convert->src_truncate_statement = 'DELETE FROM '; break; @@ -728,6 +730,7 @@ class install_convert extends module switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $convert->truncate_statement = 'DELETE FROM '; break; diff --git a/phpBB/language/en/install.php b/phpBB/language/en/install.php index 081361f661..caefc1219d 100644 --- a/phpBB/language/en/install.php +++ b/phpBB/language/en/install.php @@ -151,7 +151,8 @@ $lang = array_merge($lang, array( 'DLL_MYSQLI' => 'MySQL with MySQLi Extension', 'DLL_ORACLE' => 'Oracle', 'DLL_POSTGRES' => 'PostgreSQL', - 'DLL_SQLITE' => 'SQLite', + 'DLL_SQLITE' => 'SQLite 2', + 'DLL_SQLITE3' => 'SQLite 3', 'DLL_XML' => 'XML support [ Jabber ]', 'DLL_ZLIB' => 'zlib compression support [ gz, .tar.gz, .zip ]', 'DL_CONFIG' => 'Download config', @@ -212,6 +213,7 @@ $lang = array_merge($lang, array( <li>MySQL 3.23 or above (MySQLi supported)</li> <li>PostgreSQL 8.3+</li> <li>SQLite 2.8.2+</li> + <li>SQLite 3.6.15+</li> <li>Firebird 2.1+</li> <li>MS SQL Server 2000 or above (directly or via ODBC)</li> <li>MS SQL Server 2005 or above (native)</li> @@ -235,6 +237,7 @@ $lang = array_merge($lang, array( 'INST_ERR_DB_NO_ERROR' => 'No error message given.', 'INST_ERR_DB_NO_MYSQLI' => 'The version of MySQL installed on this machine is incompatible with the “MySQL with MySQLi Extension” option you have selected. Please try the “MySQL” option instead.', 'INST_ERR_DB_NO_SQLITE' => 'The version of the SQLite extension you have installed is too old, it must be upgraded to at least 2.8.2.', + 'INST_ERR_DB_NO_SQLITE3' => 'The version of the SQLite extension you have installed is too old, it must be upgraded to at least 3.6.15.', 'INST_ERR_DB_NO_ORACLE' => 'The version of Oracle installed on this machine requires you to set the <var>NLS_CHARACTERSET</var> parameter to <var>UTF8</var>. Either upgrade your installation to 9.2+ or change the parameter.', 'INST_ERR_DB_NO_FIREBIRD' => 'The version of Firebird installed on this machine is older than 2.1, please upgrade to a newer version.', 'INST_ERR_DB_NO_FIREBIRD_PS'=> 'The database you selected for Firebird has a page size less than 8192, it must be at least 8192.', diff --git a/phpBB/phpbb/db/driver/sqlite3.php b/phpBB/phpbb/db/driver/sqlite3.php new file mode 100644 index 0000000000..971b3e55d3 --- /dev/null +++ b/phpBB/phpbb/db/driver/sqlite3.php @@ -0,0 +1,375 @@ +<?php +/** +* +* @package dbal +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\db\driver; + +/** +* SQLite3 Database Abstraction Layer +* Minimum Requirement: 3.6.15+ +* @package dbal +*/ +class sqlite3 extends \phpbb\db\driver\driver +{ + /** + * @var string Stores errors during connection setup in case the driver is not available + */ + protected $connect_error = ''; + + /** + * @var \SQLite3 The SQLite3 database object to operate against + */ + protected $dbo = null; + + /** + * {@inheritDoc} + */ + public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) + { + $this->persistency = false; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + if (!class_exists('SQLite3', false)) + { + $this->connect_error = 'SQLite3 not found, is the extension installed?'; + return $this->sql_error(''); + } + + try + { + $this->dbo = new \SQLite3($this->server, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE); + $this->db_connect_id = true; + } + catch (Exception $e) + { + return array('message' => $e->getMessage()); + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function sql_server_info($raw = false, $use_cache = true) + { + global $cache; + + if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false) + { + $version = \SQLite3::version(); + + $this->sql_server_version = $version['versionString']; + + if (!empty($cache) && $use_cache) + { + $cache->put('sqlite_version', $this->sql_server_version); + } + } + + return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version; + } + + /** + * SQL Transaction + * + * @param string $status Should be one of the following strings: + * begin, commit, rollback + * @return bool Success/failure of the transaction query + */ + protected function _sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + return $this->dbo->exec('BEGIN IMMEDIATE'); + break; + + case 'commit': + return $this->dbo->exec('COMMIT'); + break; + + case 'rollback': + return $this->dbo->exec('ROLLBACK'); + break; + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG')) + { + $this->sql_report('start', $query); + } + + $this->last_query_text = $query; + $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; + $this->sql_add_num_queries($this->query_result); + + if ($this->query_result === false) + { + if (($this->query_result = @$this->dbo->query($query)) === false) + { + $this->sql_error($query); + } + + if (defined('DEBUG')) + { + $this->sql_report('stop', $query); + } + + if ($cache && $cache_ttl) + { + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); + } + } + else if (defined('DEBUG')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + + return $this->query_result; + } + + /** + * Build LIMIT query + * + * @param string $query The SQL query to execute + * @param int $total The number of rows to select + * @param int $offset + * @param int $cache_ttl Either 0 to avoid caching or + * the time in seconds which the result shall be kept in cache + * @return mixed Buffered, seekable result handle, false on error + */ + protected function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + $this->query_result = false; + + // if $total is set to 0 we do not want to limit the number of rows + if ($total == 0) + { + $total = -1; + } + + $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); + + return $this->sql_query($query, $cache_ttl); + } + + /** + * {@inheritDoc} + */ + public function sql_affectedrows() + { + return ($this->db_connect_id) ? $this->dbo->changes() : false; + } + + /** + * {@inheritDoc} + */ + public function sql_fetchrow($query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + { + return $cache->sql_fetchrow($query_id); + } + + return is_object($query_id) ? $query_id->fetchArray(SQLITE3_ASSOC) : false; + } + + /** + * {@inheritDoc} + */ + public function sql_nextid() + { + return ($this->db_connect_id) ? $this->dbo->lastInsertRowID() : false; + } + + /** + * {@inheritDoc} + */ + public function sql_freeresult($query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + { + return $cache->sql_freeresult($query_id); + } + + if ($query_id) + { + return @$query_id->finalize(); + } + } + + /** + * {@inheritDoc} + */ + public function sql_escape($msg) + { + return \SQLite3::escapeString($msg); + } + + /** + * {@inheritDoc} + * + * For SQLite an underscore is a not-known character... + */ + public function sql_like_expression($expression) + { + // Unlike LIKE, GLOB is case sensitive (unfortunatly). SQLite users need to live with it! + // We only catch * and ? here, not the character map possible on file globbing. + $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression); + + $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression); + $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression); + + return 'GLOB \'' . $this->sql_escape($expression) . '\''; + } + + /** + * return sql error array + * + * @return array + */ + protected function _sql_error() + { + if (class_exists('SQLite3', false)) + { + $error = array( + 'message' => $this->dbo->lastErrorMsg(), + 'code' => $this->dbo->lastErrorCode(), + ); + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); + } + + return $error; + } + + /** + * Build db-specific query data + * + * @param string $stage Available stages: FROM, WHERE + * @param mixed $data A string containing the CROSS JOIN query or an array of WHERE clauses + * + * @return string The db-specific query fragment + */ + protected function _sql_custom_build($stage, $data) + { + return $data; + } + + /** + * Close sql connection + * + * @return bool False if failure + */ + protected function _sql_close() + { + return $this->dbo->close(); + } + + /** + * Build db-specific report + * + * @param string $mode Available modes: display, start, stop, + * add_select_row, fromcache, record_fromcache + * @param string $query The Query that should be explained + * @return mixed Either a full HTML page, boolean or null + */ + protected function _sql_report($mode, $query = '') + { + switch ($mode) + { + case 'start': + + $explain_query = $query; + if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + + if (preg_match('/^SELECT/', $explain_query)) + { + $html_table = false; + + if ($result = $this->dbo->query("EXPLAIN QUERY PLAN $explain_query")) + { + while ($row = $result->fetchArray(SQLITE3_ASSOC)) + { + $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); + } + } + + if ($html_table) + { + $this->html_hold .= '</table>'; + } + } + + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = $this->dbo->query($query); + while ($void = $result->fetchArray(SQLITE3_ASSOC)) + { + // Take the time spent on parsing rows into account + } + + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $this->sql_report('record_fromcache', $query, $endtime, $splittime); + + break; + } + } +} diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools.php index 2b0132075b..a983ed91b5 100644 --- a/phpBB/phpbb/db/tools.php +++ b/phpBB/phpbb/db/tools.php @@ -257,6 +257,36 @@ class tools 'VARBINARY' => 'blob', ), + 'sqlite3' => array( + 'INT:' => 'INT(%d)', + 'BINT' => 'BIGINT(20)', + 'UINT' => 'INTEGER UNSIGNED', + 'UINT:' => 'INTEGER UNSIGNED', + 'TINT:' => 'TINYINT(%d)', + 'USINT' => 'INTEGER UNSIGNED', + 'BOOL' => 'INTEGER UNSIGNED', + 'VCHAR' => 'VARCHAR(255)', + 'VCHAR:' => 'VARCHAR(%d)', + 'CHAR:' => 'CHAR(%d)', + 'XSTEXT' => 'TEXT(65535)', + 'STEXT' => 'TEXT(65535)', + 'TEXT' => 'TEXT(65535)', + 'MTEXT' => 'MEDIUMTEXT(16777215)', + 'XSTEXT_UNI'=> 'TEXT(65535)', + 'STEXT_UNI' => 'TEXT(65535)', + 'TEXT_UNI' => 'TEXT(65535)', + 'MTEXT_UNI' => 'MEDIUMTEXT(16777215)', + 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED', + 'DECIMAL' => 'DECIMAL(5,2)', + 'DECIMAL:' => 'DECIMAL(%d,2)', + 'PDECIMAL' => 'DECIMAL(6,3)', + 'PDECIMAL:' => 'DECIMAL(%d,3)', + 'VCHAR_UNI' => 'VARCHAR(255)', + 'VCHAR_UNI:'=> 'VARCHAR(%d)', + 'VCHAR_CI' => 'VARCHAR(255)', + 'VARBINARY' => 'BLOB', + ), + 'postgres' => array( 'INT:' => 'INT4', 'BINT' => 'INT8', @@ -299,7 +329,7 @@ class tools * A list of supported DBMS. We change this class to support more DBMS, the DBMS itself only need to follow some rules. * @var array */ - var $supported_dbms = array('firebird', 'mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite'); + var $supported_dbms = array('firebird', 'mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite', 'sqlite3'); /** * This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array). @@ -389,6 +419,13 @@ class tools WHERE type = "table"'; break; + case 'sqlite3': + $sql = 'SELECT name + FROM sqlite_master + WHERE type = "table" + AND name <> "sqlite_sequence"'; + break; + case 'mssql': case 'mssql_odbc': case 'mssqlnative': @@ -567,6 +604,7 @@ class tools case 'mysql_41': case 'postgres': case 'sqlite': + case 'sqlite3': $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')'; break; @@ -604,6 +642,7 @@ class tools case 'mysql_40': case 'sqlite': + case 'sqlite3': $table_sql .= "\n);"; $statements[] = $table_sql; break; @@ -722,7 +761,7 @@ class tools $sqlite = false; // For SQLite we need to perform the schema changes in a much more different way - if ($this->db->sql_layer == 'sqlite' && $this->return_statements) + if (($this->db->sql_layer == 'sqlite' || $this->db->sql_layer == 'sqlite3') && $this->return_statements) { $sqlite_data = array(); $sqlite = true; @@ -1140,6 +1179,7 @@ class tools break; case 'sqlite': + case 'sqlite3': $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' @@ -1273,6 +1313,7 @@ class tools break; case 'sqlite': + case 'sqlite3': $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; @@ -1293,6 +1334,7 @@ class tools case 'oracle': case 'postgres': case 'sqlite': + case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } @@ -1377,6 +1419,7 @@ class tools break; case 'sqlite': + case 'sqlite3': $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; @@ -1390,7 +1433,7 @@ class tools continue; } - if ($this->sql_layer == 'sqlite' && !$row['unique']) + if (($this->sql_layer == 'sqlite' || $this->sql_layer == 'sqlite3') && !$row['unique']) { continue; } @@ -1418,6 +1461,7 @@ class tools case 'firebird': case 'postgres': case 'sqlite': + case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } @@ -1629,11 +1673,17 @@ class tools break; case 'sqlite': + case 'sqlite3': $return_array['primary_key_set'] = false; if (isset($column_data[2]) && $column_data[2] == 'auto_increment') { $sql .= ' INTEGER PRIMARY KEY'; $return_array['primary_key_set'] = true; + + if ($this->sql_layer === 'sqlite3') + { + $sql .= ' AUTOINCREMENT'; + } } else { @@ -1770,67 +1820,63 @@ class tools break; case 'sqlite': - if ($inline && $this->return_statements) { return $column_name . ' ' . $column_data['column_type_sql']; } - if (version_compare(sqlite_libversion(), '3.0') == -1) + $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); + if (empty($recreate_queries)) { - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - break; - } + break; + } - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); + $statements[] = 'begin'; - $statements[] = 'begin'; + $sql_create_table = array_shift($recreate_queries); - // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; + // Create a backup table and populate it, destroy the existing one + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); + $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; + $statements[] = 'DROP TABLE ' . $table_name; - preg_match('#\((.*)\)#s', $row['sql'], $matches); + preg_match('#\((.*)\)#s', $sql_create_table, $matches); - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); - $column_list = array(); + $new_table_cols = trim($matches[1]); + $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); + $column_list = array(); - foreach ($old_table_cols as $declaration) + foreach ($old_table_cols as $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if ($entities[0] == 'PRIMARY') { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY') - { - continue; - } - $column_list[] = $entities[0]; + continue; } + $column_list[] = $entities[0]; + } - $columns = implode(',', $column_list); + $columns = implode(',', $column_list); - $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols; + $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols; - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + // create a new table and fill it up. destroy the temp one + $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; + $statements = array_merge($statements, $recreate_queries); - $statements[] = 'commit'; - } - else + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; + $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + + $statements[] = 'commit'; + break; + + case 'sqlite3': + if ($inline && $this->return_statements) { - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' [' . $column_data['column_type_sql'] . ']'; + return $column_name . ' ' . $column_data['column_type_sql']; } + + $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql']; break; } @@ -1908,67 +1954,61 @@ class tools break; case 'sqlite': + case 'sqlite3': if ($inline && $this->return_statements) { return $column_name; } - if (version_compare(sqlite_libversion(), '3.0') == -1) + $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name, $column_name); + if (empty($recreate_queries)) { - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - break; - } + break; + } - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); + $statements[] = 'begin'; - $statements[] = 'begin'; + $sql_create_table = array_shift($recreate_queries); - // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; + // Create a backup table and populate it, destroy the existing one + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); + $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; + $statements[] = 'DROP TABLE ' . $table_name; - preg_match('#\((.*)\)#s', $row['sql'], $matches); + preg_match('#\((.*)\)#s', $sql_create_table, $matches); - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); - $column_list = array(); + $new_table_cols = trim($matches[1]); + $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); + $column_list = array(); - foreach ($old_table_cols as $declaration) + foreach ($old_table_cols as $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name) { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name) - { - continue; - } - $column_list[] = $entities[0]; + continue; } + $column_list[] = $entities[0]; + } - $columns = implode(',', $column_list); - - $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols); - - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + $columns = implode(',', $column_list); - $statements[] = 'commit'; - } - else + $new_table_cols = trim(preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols)); + if (substr($new_table_cols, -1) === ',') { - $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name; + // Remove the comma from the last entry again + $new_table_cols = substr($new_table_cols, 0, -1); } + + // create a new table and fill it up. destroy the temp one + $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; + $statements = array_merge($statements, $recreate_queries); + + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; + $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + + $statements[] = 'commit'; break; } @@ -1998,6 +2038,7 @@ class tools case 'oracle': case 'postgres': case 'sqlite': + case 'sqlite3': $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name; break; } @@ -2104,35 +2145,29 @@ class tools break; case 'sqlite': + case 'sqlite3': if ($inline && $this->return_statements) { return $column; } - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) + $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); + if (empty($recreate_queries)) { break; } - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - $statements[] = 'begin'; + $sql_create_table = array_shift($recreate_queries); + // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; - preg_match('#\((.*)\)#s', $row['sql'], $matches); + preg_match('#\((.*)\)#s', $sql_create_table, $matches); $new_table_cols = trim($matches[1]); $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); @@ -2152,6 +2187,8 @@ class tools // create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));'; + $statements = array_merge($statements, $recreate_queries); + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; @@ -2182,6 +2219,7 @@ class tools case 'postgres': case 'oracle': case 'sqlite': + case 'sqlite3': $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; @@ -2225,6 +2263,7 @@ class tools case 'postgres': case 'oracle': case 'sqlite': + case 'sqlite3': $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; @@ -2316,6 +2355,7 @@ class tools break; case 'sqlite': + case 'sqlite3': $sql = "PRAGMA index_info('" . $table_name . "');"; $col = 'name'; break; @@ -2335,6 +2375,7 @@ class tools case 'oracle': case 'postgres': case 'sqlite': + case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } @@ -2488,35 +2529,29 @@ class tools break; case 'sqlite': + case 'sqlite3': if ($inline && $this->return_statements) { return $column_name . ' ' . $column_data['column_type_sql']; } - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) + $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); + if (empty($recreate_queries)) { break; } - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - $statements[] = 'begin'; + $sql_create_table = array_shift($recreate_queries); + // Create a temp table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; - preg_match('#\((.*)\)#s', $row['sql'], $matches); + preg_match('#\((.*)\)#s', $sql_create_table, $matches); $new_table_cols = trim($matches[1]); $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); @@ -2534,8 +2569,10 @@ class tools $columns = implode(',', $column_list); - // create a new table and fill it up. destroy the temp one + // Create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');'; + $statements = array_merge($statements, $recreate_queries); + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; @@ -2701,4 +2738,75 @@ class tools return $this->is_sql_server_2000; } + + /** + * Returns the Queries which are required to recreate a table including indexes + * + * @param string $table_name + * @param string $remove_column When we drop a column, we remove the column + * from all indexes. If the index has no other + * column, we drop it completly. + * @return array + */ + protected function sqlite_get_recreate_table_queries($table_name, $remove_column = '') + { + $queries = array(); + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'table' + AND name = '{$table_name}'"; + $result = $this->db->sql_query($sql); + $sql_create_table = $this->db->sql_fetchfield('sql'); + $this->db->sql_freeresult($result); + + if (!$sql_create_table) + { + return array(); + } + $queries[] = $sql_create_table; + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'index' + AND tbl_name = '{$table_name}'"; + $result = $this->db->sql_query($sql); + while ($sql_create_index = $this->db->sql_fetchfield('sql')) + { + if ($remove_column) + { + $match = array(); + preg_match('#(?:[\w ]+)\((.*)\)#', $sql_create_index, $match); + if (!isset($match[1])) + { + continue; + } + + // Find and remove $remove_column from the index + $columns = explode(', ', $match[1]); + $found_column = array_search($remove_column, $columns); + if ($found_column !== false) + { + unset($columns[$found_column]); + + // If the column list is not empty add the index to the list + if (!empty($columns)) + { + $queries[] = str_replace($match[1], implode(', ', $columns), $sql_create_index); + } + } + else + { + $queries[] = $sql_create_index; + } + } + else + { + $queries[] = $sql_create_index; + } + } + $this->db->sql_freeresult($result); + + return $queries; + } } diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php index 7d51d164c7..f3b229cc7c 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -768,6 +768,7 @@ class fulltext_native extends \phpbb\search\base break; case 'sqlite': + case 'sqlite3': $sql_array_count['SELECT'] = ($type == 'posts') ? 'DISTINCT p.post_id' : 'DISTINCT p.topic_id'; $sql = 'SELECT COUNT(' . (($type == 'posts') ? 'post_id' : 'topic_id') . ') as total_results FROM (' . $this->db->sql_build_query('SELECT', $sql_array_count) . ')'; @@ -997,7 +998,7 @@ class fulltext_native extends \phpbb\search\base } else { - if ($this->db->sql_layer == 'sqlite') + if ($this->db->sql_layer == 'sqlite' || $this->db->sql_layer == 'sqlite3') { $sql = 'SELECT COUNT(topic_id) as total_results FROM (SELECT DISTINCT t.topic_id'; @@ -1014,7 +1015,7 @@ class fulltext_native extends \phpbb\search\base $post_visibility $sql_fora AND t.topic_id = p.topic_id - $sql_time" . (($this->db->sql_layer == 'sqlite') ? ')' : ''); + $sql_time" . (($this->db->sql_layer == 'sqlite' || $this->db->sql_layer == 'sqlite3') ? ')' : ''); } $result = $this->db->sql_query($sql); @@ -1481,6 +1482,7 @@ class fulltext_native extends \phpbb\search\base switch ($this->db->sql_layer) { case 'sqlite': + case 'sqlite3': case 'firebird': $this->db->sql_query('DELETE FROM ' . SEARCH_WORDLIST_TABLE); $this->db->sql_query('DELETE FROM ' . SEARCH_WORDMATCH_TABLE); diff --git a/phpBB/viewonline.php b/phpBB/viewonline.php index 9b462b2656..52fd9f640c 100644 --- a/phpBB/viewonline.php +++ b/phpBB/viewonline.php @@ -101,6 +101,7 @@ if (!$show_guests) switch ($db->sql_layer) { case 'sqlite': + case 'sqlite3': $sql = 'SELECT COUNT(session_ip) as num_guests FROM ( SELECT DISTINCT session_ip diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 887dad5b50..796a6e57cf 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -53,6 +53,7 @@ class phpbb_database_test_connection_manager switch ($this->dbms['PDO']) { case 'sqlite2': + case 'sqlite': // SQLite3 driver $dsn .= $this->config['dbhost']; break; @@ -191,6 +192,7 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { case 'phpbb\db\driver\sqlite': + case 'phpbb\db\driver\sqlite3': case 'phpbb\db\driver\firebird': $this->connect(); // Drop all of the tables @@ -272,6 +274,13 @@ class phpbb_database_test_connection_manager WHERE type = "table"'; break; + case 'phpbb\db\driver\sqlite3': + $sql = 'SELECT name + FROM sqlite_master + WHERE type = "table" + AND name <> "sqlite_sequence"'; + break; + case 'phpbb\db\driver\mssql': case 'phpbb\db\driver\mssql_odbc': case 'phpbb\db\driver\mssqlnative': @@ -436,6 +445,11 @@ class phpbb_database_test_connection_manager 'DELIM' => ';', 'PDO' => 'sqlite2', ), + 'phpbb\db\driver\sqlite3' => array( + 'SCHEMA' => 'sqlite', + 'DELIM' => ';', + 'PDO' => 'sqlite', + ), ); if (isset($available_dbms[$dbms])) @@ -623,6 +637,14 @@ class phpbb_database_test_connection_manager $queries[] = 'SELECT ' . implode(', ', $setval_queries); } break; + + case 'phpbb\db\driver\sqlite3': + /** + * Just delete all of the sequences. When an insertion occurs, the sequence will be automatically + * re-created from the key with the AUTOINCREMENT attribute + */ + $queries[] = 'DELETE FROM sqlite_sequence'; + break; } foreach ($queries as $query) diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index 2f225fe7af..aba63a0498 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -104,7 +104,19 @@ class phpbb_test_case_helpers { $config = array(); - if (extension_loaded('sqlite') && version_compare(PHPUnit_Runner_Version::id(), '3.4.15', '>=')) + + if (extension_loaded('sqlite3')) + { + $config = array_merge($config, array( + 'dbms' => 'phpbb\db\driver\sqlite3', + 'dbhost' => dirname(__FILE__) . '/../phpbb_unit_tests.sqlite3', // filename + 'dbport' => '', + 'dbname' => '', + 'dbuser' => '', + 'dbpasswd' => '', + )); + } + else if (extension_loaded('sqlite')) { $config = array_merge($config, array( 'dbms' => 'phpbb\db\driver\sqlite', diff --git a/travis/phpunit-postgres-travis.xml b/travis/phpunit-postgres-travis.xml index 88d9e0f46a..42dde1e1ee 100644 --- a/travis/phpunit-postgres-travis.xml +++ b/travis/phpunit-postgres-travis.xml @@ -29,8 +29,6 @@ </groups> <php> - <!-- "Real" test database --> - <!-- uncomment, otherwise sqlite memory runs --> <server name="PHPBB_TEST_DBMS" value="phpbb\db\driver\postgres"/> <server name="PHPBB_TEST_DBHOST" value="localhost" /> <server name="PHPBB_TEST_DBPORT" value="5432" /> diff --git a/travis/phpunit-sqlite3-travis.xml b/travis/phpunit-sqlite3-travis.xml new file mode 100644 index 0000000000..e7dd5f300e --- /dev/null +++ b/travis/phpunit-sqlite3-travis.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<phpunit backupGlobals="true" + backupStaticAttributes="true" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + syntaxCheck="true" + strict="true" + verbose="true" + bootstrap="../tests/bootstrap.php"> + <testsuites> + <testsuite name="phpBB Test Suite"> + <directory suffix="_test.php">../tests/</directory> + <exclude>tests/functional</exclude> + <exclude>tests/lint_test.php</exclude> + </testsuite> + <testsuite name="phpBB Functional Tests"> + <directory suffix="_test.php" phpVersion="5.3.19" phpVersionOperator=">=">../tests/functional</directory> + </testsuite> + </testsuites> + + <groups> + <exclude> + <group>slow</group> + </exclude> + </groups> + + <php> + <!--server name="PHPBB_TEST_DBMS" value="phpbb\db\driver\sqlite3" /--> + <!--server name="PHPBB_TEST_DBHOST" value="../phpbb_unit_tests.sqlite3" /--> + <!--server name="PHPBB_TEST_DBPORT" value="" /--> + <!--server name="PHPBB_TEST_DBNAME" value="" /--> + <!--server name="PHPBB_TEST_DBUSER" value="" /--> + <!--server name="PHPBB_TEST_DBPASSWD" value="" /--> + <server name="PHPBB_TEST_REDIS_HOST" value="localhost" /> + <server name="PHPBB_TEST_TABLE_PREFIX" value="phpbb_"/> + <server name="PHPBB_FUNCTIONAL_URL" value="http://localhost/" /> + </php> +</phpunit> |