Merge branch '2'

# Conflicts:
 #	.travis.yml
This commit is contained in:
Robbie Averill 2019-01-09 09:36:57 +01:00
commit 6ca8572ce5
6 changed files with 216 additions and 40 deletions

View File

@ -6,35 +6,50 @@ cache:
directories:
- $HOME/.composer/cache/files
php:
- 7.1
- 7.2
- nightly
env:
global:
- DB=SQLITE
- PDO=1
matrix:
fast_finish: true
include:
- php: 5.6
env:
- CORE_VERSION=1.0.x-dev
- PDO=0
- php: 7.0
env:
- CORE_VERSION=1.1.x-dev
- PDO=1
- php: 7.1
env:
- CORE_VERSION=4.2.x-dev
- PDO=0
- php: 7.2
env: PDO=0 PHPCS_TEST=1
allow_failure:
- php: nightly
env:
- CORE_VERSION=4.3.x-dev
- PDO=0
- php: 7.3
env:
- CORE_VERSION=4.x-dev
- PDO=1
- PHPCS_TEST=1
before_script:
# Init PHP
- phpenv rehash
- phpenv config-rm xdebug.ini
- phpenv config-rm xdebug.ini || true
- export PATH=~/.composer/vendor/bin:$PATH
- echo 'memory_limit = 2048M' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
# Install composer dependencies
- composer validate
- composer require --no-update silverstripe/recipe-cms:2.x-dev
- composer install --prefer-source --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
- composer require --no-update silverstripe/recipe-cms:$CORE_VERSION
- composer install --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
- if [[ $PHPCS_TEST ]]; then composer global require squizlabs/php_codesniffer:^3 --prefer-dist --no-interaction --no-progress --no-suggest -o; fi
script:

View File

@ -1,6 +1,7 @@
# SQLite3 Module
[![Build Status](https://travis-ci.org/silverstripe-labs/silverstripe-sqlite3.png?branch=master)](https://travis-ci.org/silverstripe-labs/silverstripe-sqlite3)
[![Build Status](https://travis-ci.org/silverstripe/silverstripe-sqlite3.png?branch=master)](https://travis-ci.org/silverstripe/silverstripe-sqlite3)
[![SilverStripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
## Maintainer Contact

View File

@ -5,28 +5,28 @@ SilverStripe\Core\Injector\Injector:
SQLite3PDODatabase:
class: SilverStripe\SQLite\SQLite3Database
properties:
connector: %$PDOConnector
schemaManager: %$SQLite3SchemaManager
queryBuilder: %$SQLite3QueryBuilder
connector: '%$PDOConnector'
schemaManager: '%$SQLite3SchemaManager'
queryBuilder: '%$SQLite3QueryBuilder'
SQLite3Database:
class: SilverStripe\SQLite\SQLite3Database
properties:
connector: %$SQLite3Connector
schemaManager: %$SQLite3SchemaManager
queryBuilder: %$SQLite3QueryBuilder
connector: '%$SQLite3Connector'
schemaManager: '%$SQLite3SchemaManager'
queryBuilder: '%$SQLite3QueryBuilder'
# Legacy connector names
SQLiteDatabase:
class: SilverStripe\SQLite\SQLite3Database
properties:
connector: %$SQLite3Connector
schemaManager: %$SQLite3SchemaManager
queryBuilder: %$SQLite3QueryBuilder
connector: '%$SQLite3Connector'
schemaManager: '%$SQLite3SchemaManager'
queryBuilder: '%$SQLite3QueryBuilder'
SQLitePDODatabase:
class: SilverStripe\SQLite\SQLite3Database
properties:
connector: %$SQLite3Connector
schemaManager: %$SQLite3SchemaManager
queryBuilder: %$SQLite3QueryBuilder
connector: '%$SQLite3Connector'
schemaManager: '%$SQLite3SchemaManager'
queryBuilder: '%$SQLite3QueryBuilder'
SQLite3Connector:
class: SilverStripe\SQLite\SQLite3Connector
type: prototype

View File

@ -60,6 +60,16 @@ class SQLite3Database extends Database
*/
protected $livesInMemory = false;
/**
* @var bool
*/
protected $transactionNesting = 0;
/**
* @var array
*/
protected $transactionSavepoints = [];
/**
* List of default pragma values
*
@ -348,7 +358,7 @@ class SQLite3Database extends Database
"(Title LIKE '%$relevanceKeywords%' OR MenuTitle LIKE '%$relevanceKeywords%'"
. " OR Content LIKE '%$relevanceKeywords%' OR MetaDescription LIKE '%$relevanceKeywords%')"
. " + (Title LIKE '%$htmlEntityRelevanceKeywords%' OR MenuTitle LIKE '%$htmlEntityRelevanceKeywords%'"
. " OR Content LIKE '%$htmlEntityRelevanceKeywords%' OR MetaDescriptio "
. " OR Content LIKE '%$htmlEntityRelevanceKeywords%' OR MetaDescription "
. " LIKE '%$htmlEntityRelevanceKeywords%')";
$relevance[$fileClass] = "(Name LIKE '%$relevanceKeywords%' OR Title LIKE '%$relevanceKeywords%')";
} else {
@ -465,26 +475,148 @@ class SQLite3Database extends Database
public function transactionStart($transaction_mode = false, $session_characteristics = false)
{
$this->query('BEGIN');
if ($this->transactionDepth()) {
$this->transactionSavepoint('NESTEDTRANSACTION' . $this->transactionDepth());
} else {
$this->query('BEGIN');
$this->transactionDepthIncrease();
}
}
public function transactionSavepoint($savepoint)
{
$this->query("SAVEPOINT \"$savepoint\"");
$this->transactionDepthIncrease($savepoint);
}
/**
* Fetch the name of the most recent savepoint
*
* @return string
*/
protected function getTransactionSavepointName()
{
return end($this->transactionSavepoints);
}
public function transactionRollback($savepoint = false)
{
// Named transaction
if ($savepoint) {
$this->query("ROLLBACK TO $savepoint;");
$this->transactionDepthDecrease();
return true;
}
// Fail if transaction isn't available
if (!$this->transactionDepth()) {
return false;
}
if ($this->transactionIsNested()) {
$this->transactionRollback($this->getTransactionSavepointName());
} else {
$this->query('ROLLBACK;');
$this->transactionDepthDecrease();
}
return true;
}
public function transactionDepth()
{
return $this->transactionNesting;
}
public function transactionEnd($chain = false)
{
$this->query('COMMIT;');
// Fail if transaction isn't available
if (!$this->transactionDepth()) {
return false;
}
if ($this->transactionIsNested()) {
$savepoint = $this->getTransactionSavepointName();
$this->query('RELEASE ' . $savepoint);
$this->transactionDepthDecrease();
} else {
$this->query('COMMIT;');
$this->resetTransactionNesting();
}
if ($chain) {
$this->transactionStart();
}
return true;
}
/**
* Indicate whether or not the current transaction is nested
* Returns false if there are no transactions, or the open
* transaction is the 'outer' transaction, i.e. not nested.
*
* @return bool
*/
protected function transactionIsNested()
{
return $this->transactionNesting > 1;
}
/**
* Increase the nested transaction level by one
* savepoint tracking is optional because BEGIN
* opens a transaction, but is not a named reference
*
* @param string $savepoint
*/
protected function transactionDepthIncrease($savepoint = null)
{
++$this->transactionNesting;
if ($savepoint) {
array_push($this->transactionSavepoints, $savepoint);
}
}
/**
* Decrease the nested transaction level by one
* and reduce the savepoint tracking if we are
* nesting, as the last one is no longer valid
*/
protected function transactionDepthDecrease()
{
if ($this->transactionIsNested()) {
array_pop($this->transactionSavepoints);
}
--$this->transactionNesting;
}
/**
* In error condition, set transactionNesting to zero
*/
protected function resetTransactionNesting()
{
$this->transactionNesting = 0;
$this->transactionSavepoints = [];
}
public function query($sql, $errorLevel = E_USER_ERROR)
{
return parent::query($sql, $errorLevel);
}
public function preparedQuery($sql, $parameters, $errorLevel = E_USER_ERROR)
{
return parent::preparedQuery($sql, $parameters, $errorLevel);
}
/**
* Inspect a SQL query prior to execution
* @deprecated 2.2.0:3.0.0
* @param string $sql
*/
protected function inspectQuery($sql)
{
// no-op
}
public function clearTable($table)

View File

@ -55,6 +55,11 @@ class SQLite3Query extends Query
*/
public function numRecords()
{
// Some queries are not iterable using fetchArray like CREATE statement
if (!$this->handle->numColumns()) {
return 0;
}
$this->handle->reset();
$c=0;
while ($this->handle->fetchArray()) {

View File

@ -2,10 +2,11 @@
namespace SilverStripe\SQLite;
use Exception;
use SilverStripe\Control\Director;
use SilverStripe\Dev\Debug;
use SilverStripe\ORM\Connect\DBSchemaManager;
use Exception;
use SQLite3;
/**
* SQLite schema manager class
@ -275,21 +276,22 @@ class SQLite3SchemaManager extends DBSchemaManager
}
$queries = array(
"BEGIN TRANSACTION",
"CREATE TABLE \"{$tableName}_alterfield_{$fieldName}\"(" . implode(',', $newColsSpec) . ")",
"INSERT INTO \"{$tableName}_alterfield_{$fieldName}\" SELECT {$fieldNameList} FROM \"$tableName\"",
"DROP TABLE \"$tableName\"",
"ALTER TABLE \"{$tableName}_alterfield_{$fieldName}\" RENAME TO \"$tableName\"",
"COMMIT"
);
// Remember original indexes
$indexList = $this->indexList($tableName);
// Then alter the table column
foreach ($queries as $query) {
$this->query($query.';');
}
$database = $this->database;
$database->withTransaction(function () use ($database, $queries, $indexList) {
foreach ($queries as $query) {
$database->query($query . ';');
}
});
// Recreate the indexes
foreach ($indexList as $indexName => $indexSpec) {
@ -318,21 +320,22 @@ class SQLite3SchemaManager extends DBSchemaManager
$oldColsStr = implode(',', $oldCols);
$newColsSpecStr = implode(',', $newColsSpec);
$queries = array(
"BEGIN TRANSACTION",
"CREATE TABLE \"{$tableName}_renamefield_{$oldName}\" ({$newColsSpecStr})",
"INSERT INTO \"{$tableName}_renamefield_{$oldName}\" SELECT {$oldColsStr} FROM \"$tableName\"",
"DROP TABLE \"$tableName\"",
"ALTER TABLE \"{$tableName}_renamefield_{$oldName}\" RENAME TO \"$tableName\"",
"COMMIT"
);
// Remember original indexes
$oldIndexList = $this->indexList($tableName);
// Then alter the table column
foreach ($queries as $query) {
$this->query($query.';');
}
$database = $this->database;
$database->withTransaction(function () use ($database, $queries) {
foreach ($queries as $query) {
$database->query($query . ';');
}
});
// Recreate the indexes
foreach ($oldIndexList as $indexName => $indexSpec) {
@ -429,6 +432,15 @@ class SQLite3SchemaManager extends DBSchemaManager
return $this->buildSQLiteIndexName($table, $index);
}
protected function convertIndexSpec($indexSpec)
{
$supportedIndexTypes = ['index', 'unique'];
if (isset($indexSpec['type']) && !in_array($indexSpec['type'], $supportedIndexTypes)) {
$indexSpec['type'] = 'index';
}
return parent::convertIndexSpec($indexSpec);
}
public function indexList($table)
{
$indexList = array();
@ -540,7 +552,18 @@ class SQLite3SchemaManager extends DBSchemaManager
// Set default
if (!empty($values['default'])) {
$default = str_replace(array('"', "'", "\\", "\0"), "", $values['default']);
/*
On escaping strings:
https://www.sqlite.org/lang_expr.html
"A string constant is formed by enclosing the string in single quotes ('). A single quote within
the string can be encoded by putting two single quotes in a row - as in Pascal. C-style escapes
using the backslash character are not supported because they are not standard SQL."
Also, there is a nifty PHP function for this. However apparently one must still be cautious of
the null character ('\0' or 0x0), as per https://bugs.php.net/bug.php?id=63419
*/
$default = SQLite3::escapeString(str_replace("\0", "", $values['default']));
return "TEXT DEFAULT '$default'";
} else {
return 'TEXT';