2010-12-14 16:26:35 +00:00
|
|
|
<?php
|
|
|
|
|
|
2019-06-05 21:25:46 +00:00
|
|
|
use Psr\Log\NullLogger;
|
2017-02-07 17:36:12 +00:00
|
|
|
use Wikimedia\Rdbms\Blob;
|
2017-02-07 04:49:57 +00:00
|
|
|
use Wikimedia\Rdbms\Database;
|
|
|
|
|
use Wikimedia\Rdbms\DatabaseSqlite;
|
2019-11-08 20:15:35 +00:00
|
|
|
use Wikimedia\Rdbms\ResultWrapper;
|
2019-06-05 21:25:46 +00:00
|
|
|
use Wikimedia\Rdbms\TransactionProfiler;
|
2017-02-07 17:36:12 +00:00
|
|
|
|
2010-12-14 16:26:35 +00:00
|
|
|
/**
|
|
|
|
|
* @group sqlite
|
2012-01-18 15:50:00 +00:00
|
|
|
* @group Database
|
2012-12-03 08:17:24 +00:00
|
|
|
* @group medium
|
2010-12-14 16:26:35 +00:00
|
|
|
*/
|
2019-06-26 02:33:14 +00:00
|
|
|
class DatabaseSqliteTest extends \MediaWikiIntegrationTestCase {
|
2019-06-05 21:25:46 +00:00
|
|
|
/** @var DatabaseSqlite */
|
2014-04-24 16:06:21 +00:00
|
|
|
protected $db;
|
2010-12-14 16:26:35 +00:00
|
|
|
|
2022-02-24 04:06:11 +00:00
|
|
|
/** @var array|null */
|
|
|
|
|
protected $currentTableInfo;
|
|
|
|
|
|
2021-07-22 03:11:47 +00:00
|
|
|
protected function setUp(): void {
|
2012-10-08 10:56:20 +00:00
|
|
|
parent::setUp();
|
|
|
|
|
|
2010-12-14 16:26:35 +00:00
|
|
|
if ( !Sqlite::isPresent() ) {
|
|
|
|
|
$this->markTestSkipped( 'No SQLite support detected' );
|
|
|
|
|
}
|
2019-11-08 20:15:35 +00:00
|
|
|
$this->db = $this->newMockDb();
|
|
|
|
|
if ( version_compare( $this->db->getServerVersion(), '3.6.0', '<' ) ) {
|
|
|
|
|
$this->markTestSkipped( "SQLite at least 3.6 required, {$this->db->getServerVersion()} found" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2021-01-14 08:20:36 +00:00
|
|
|
* @param string|null $version
|
|
|
|
|
* @param string|null &$sqlDump
|
2019-11-08 20:15:35 +00:00
|
|
|
* @return \PHPUnit\Framework\MockObject\MockObject|DatabaseSqlite
|
|
|
|
|
*/
|
|
|
|
|
private function newMockDb( $version = null, &$sqlDump = null ) {
|
|
|
|
|
$mock = $this->getMockBuilder( DatabaseSqlite::class )
|
2019-06-05 21:25:46 +00:00
|
|
|
->setConstructorArgs( [ [
|
|
|
|
|
'dbFilePath' => ':memory:',
|
2019-08-20 09:28:29 +00:00
|
|
|
'dbname' => 'Foo',
|
2019-11-08 20:15:35 +00:00
|
|
|
'schema' => null,
|
2019-06-05 21:25:46 +00:00
|
|
|
'host' => false,
|
|
|
|
|
'user' => false,
|
|
|
|
|
'password' => false,
|
|
|
|
|
'tablePrefix' => '',
|
|
|
|
|
'cliMode' => true,
|
|
|
|
|
'agent' => 'unit-tests',
|
2021-03-10 01:38:23 +00:00
|
|
|
'serverName' => null,
|
2019-06-05 21:25:46 +00:00
|
|
|
'flags' => DBO_DEFAULT,
|
2022-02-24 04:06:11 +00:00
|
|
|
'variables' => [ 'synchronous' => 'NORMAL', 'temp_store' => 'MEMORY' ],
|
2019-06-05 21:25:46 +00:00
|
|
|
'profiler' => null,
|
2020-02-24 20:31:57 +00:00
|
|
|
'topologyRole' => Database::ROLE_STREAMING_MASTER,
|
2019-06-05 21:25:46 +00:00
|
|
|
'trxProfiler' => new TransactionProfiler(),
|
|
|
|
|
'errorLogger' => null,
|
2020-02-24 20:31:57 +00:00
|
|
|
'deprecationLogger' => new NullLogger(),
|
|
|
|
|
'srvCache' => new HashBagOStuff(),
|
2021-03-20 15:18:58 +00:00
|
|
|
] ] )->onlyMethods( array_merge(
|
2019-11-08 20:15:35 +00:00
|
|
|
[ 'query' ],
|
|
|
|
|
$version ? [ 'getServerVersion' ] : []
|
|
|
|
|
) )->getMock();
|
|
|
|
|
|
|
|
|
|
$mock->initConnection();
|
|
|
|
|
|
|
|
|
|
$sqlDump = '';
|
2021-02-07 13:10:36 +00:00
|
|
|
$mock->method( 'query' )->willReturnCallback( static function ( $sql ) use ( &$sqlDump ) {
|
2019-11-08 20:15:35 +00:00
|
|
|
$sqlDump .= "$sql;";
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
if ( $version ) {
|
|
|
|
|
$mock->method( 'getServerVersion' )->willReturn( $version );
|
2011-05-09 16:41:51 +00:00
|
|
|
}
|
2019-11-08 20:15:35 +00:00
|
|
|
|
|
|
|
|
return $mock;
|
2010-12-14 16:26:35 +00:00
|
|
|
}
|
|
|
|
|
|
2011-06-18 20:37:02 +00:00
|
|
|
private function assertResultIs( $expected, $res ) {
|
|
|
|
|
$this->assertNotNull( $res );
|
|
|
|
|
$i = 0;
|
2013-02-14 13:10:38 +00:00
|
|
|
foreach ( $res as $row ) {
|
|
|
|
|
foreach ( $expected[$i] as $key => $value ) {
|
2011-06-18 20:37:02 +00:00
|
|
|
$this->assertTrue( isset( $row->$key ) );
|
|
|
|
|
$this->assertEquals( $value, $row->$key );
|
|
|
|
|
}
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
|
|
|
|
$this->assertEquals( count( $expected ), $i, 'Unexpected number of rows' );
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-31 14:27:57 +00:00
|
|
|
public static function provideAddQuotes() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
|
|
|
|
[ // #0: empty
|
2012-10-31 14:27:57 +00:00
|
|
|
'', "''"
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ // #1: simple
|
2012-10-31 14:27:57 +00:00
|
|
|
'foo bar', "'foo bar'"
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ // #2: including quote
|
2012-10-31 14:27:57 +00:00
|
|
|
'foo\'bar', "'foo''bar'"
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2014-04-24 16:06:21 +00:00
|
|
|
// #3: including \0 (must be represented as hex, per https://bugs.php.net/bug.php?id=63419)
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
2012-10-31 14:27:57 +00:00
|
|
|
"x\0y",
|
|
|
|
|
"x'780079'",
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ // #4: blob object (must be represented as hex)
|
2012-10-31 14:27:57 +00:00
|
|
|
new Blob( "hello" ),
|
|
|
|
|
"x'68656c6c6f'",
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2017-07-20 20:17:11 +00:00
|
|
|
[ // #5: null
|
|
|
|
|
null,
|
|
|
|
|
"''",
|
|
|
|
|
],
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2012-10-31 14:27:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideAddQuotes()
|
2022-05-27 22:27:16 +00:00
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::addQuotes
|
2012-10-31 14:27:57 +00:00
|
|
|
*/
|
|
|
|
|
public function testAddQuotes( $value, $expected ) {
|
|
|
|
|
// check quoting
|
2015-03-07 12:31:08 +00:00
|
|
|
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
|
2012-10-31 14:27:57 +00:00
|
|
|
$this->assertEquals( $expected, $db->addQuotes( $value ), 'string not quoted as expected' );
|
|
|
|
|
|
|
|
|
|
// ok, quoting works as expected, now try a round trip.
|
|
|
|
|
$re = $db->query( 'select ' . $db->addQuotes( $value ) );
|
|
|
|
|
|
|
|
|
|
$this->assertTrue( $re !== false, 'query failed' );
|
|
|
|
|
|
2015-11-18 18:32:05 +00:00
|
|
|
$row = $re->fetchRow();
|
|
|
|
|
if ( $row ) {
|
2012-10-31 14:27:57 +00:00
|
|
|
if ( $value instanceof Blob ) {
|
|
|
|
|
$value = $value->fetch();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( $value, $row[0], 'string mangled by the database' );
|
|
|
|
|
} else {
|
|
|
|
|
$this->fail( 'query returned no result' );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-18 10:36:09 +00:00
|
|
|
/**
|
2022-05-27 22:27:16 +00:00
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::duplicateTableStructure
|
2013-10-18 10:36:09 +00:00
|
|
|
*/
|
2011-02-26 16:45:35 +00:00
|
|
|
public function testDuplicateTableStructure() {
|
2015-03-07 12:31:08 +00:00
|
|
|
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
|
2011-02-26 16:45:35 +00:00
|
|
|
$db->query( 'CREATE TABLE foo(foo, barfoo)' );
|
2015-08-06 09:25:16 +00:00
|
|
|
$db->query( 'CREATE INDEX index1 ON foo(foo)' );
|
|
|
|
|
$db->query( 'CREATE UNIQUE INDEX index2 ON foo(barfoo)' );
|
2011-02-26 16:45:35 +00:00
|
|
|
|
|
|
|
|
$db->duplicateTableStructure( 'foo', 'bar' );
|
2011-04-12 20:48:19 +00:00
|
|
|
$this->assertEquals( 'CREATE TABLE "bar"(foo, barfoo)',
|
2016-02-17 09:09:32 +00:00
|
|
|
$db->selectField( 'sqlite_master', 'sql', [ 'name' => 'bar' ] ),
|
2011-02-26 16:45:35 +00:00
|
|
|
'Normal table duplication'
|
|
|
|
|
);
|
2015-08-06 09:25:16 +00:00
|
|
|
$indexList = $db->query( 'PRAGMA INDEX_LIST("bar")' );
|
2022-04-28 14:04:07 +00:00
|
|
|
$index = $indexList->fetchObject();
|
2015-08-06 09:25:16 +00:00
|
|
|
$this->assertEquals( 'bar_index1', $index->name );
|
2022-07-30 05:17:41 +00:00
|
|
|
$this->assertSame( '0', (string)$index->unique );
|
2022-04-28 14:04:07 +00:00
|
|
|
$index = $indexList->fetchObject();
|
2015-08-06 09:25:16 +00:00
|
|
|
$this->assertEquals( 'bar_index2', $index->name );
|
2022-07-30 05:17:41 +00:00
|
|
|
$this->assertSame( '1', (string)$index->unique );
|
2011-02-26 16:45:35 +00:00
|
|
|
|
|
|
|
|
$db->duplicateTableStructure( 'foo', 'baz', true );
|
2011-04-12 20:48:19 +00:00
|
|
|
$this->assertEquals( 'CREATE TABLE "baz"(foo, barfoo)',
|
2016-02-17 09:09:32 +00:00
|
|
|
$db->selectField( 'sqlite_temp_master', 'sql', [ 'name' => 'baz' ] ),
|
2011-02-26 16:45:35 +00:00
|
|
|
'Creation of temporary duplicate'
|
|
|
|
|
);
|
2015-08-06 09:25:16 +00:00
|
|
|
$indexList = $db->query( 'PRAGMA INDEX_LIST("baz")' );
|
2022-04-28 14:04:07 +00:00
|
|
|
$index = $indexList->fetchObject();
|
2015-08-06 09:25:16 +00:00
|
|
|
$this->assertEquals( 'baz_index1', $index->name );
|
2022-07-30 05:17:41 +00:00
|
|
|
$this->assertSame( '0', (string)$index->unique );
|
2022-04-28 14:04:07 +00:00
|
|
|
$index = $indexList->fetchObject();
|
2015-08-06 09:25:16 +00:00
|
|
|
$this->assertEquals( 'baz_index2', $index->name );
|
2022-07-30 05:17:41 +00:00
|
|
|
$this->assertSame( '1', (string)$index->unique );
|
2020-02-24 20:31:57 +00:00
|
|
|
$this->assertSame( '0',
|
2022-07-30 05:17:41 +00:00
|
|
|
(string)$db->selectField( 'sqlite_master', 'COUNT(*)', [ 'name' => 'baz' ] ),
|
2011-02-26 16:45:35 +00:00
|
|
|
'Create a temporary duplicate only'
|
|
|
|
|
);
|
|
|
|
|
}
|
2011-09-28 19:28:19 +00:00
|
|
|
|
2013-10-18 10:36:09 +00:00
|
|
|
/**
|
2022-05-27 22:27:16 +00:00
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::duplicateTableStructure
|
2013-10-18 10:36:09 +00:00
|
|
|
*/
|
2011-02-26 16:45:35 +00:00
|
|
|
public function testDuplicateTableStructureVirtual() {
|
2015-03-07 12:31:08 +00:00
|
|
|
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
|
2011-02-26 16:45:35 +00:00
|
|
|
if ( $db->getFulltextSearchModule() != 'FTS3' ) {
|
|
|
|
|
$this->markTestSkipped( 'FTS3 not supported, cannot create virtual tables' );
|
|
|
|
|
}
|
2011-04-12 20:48:19 +00:00
|
|
|
$db->query( 'CREATE VIRTUAL TABLE "foo" USING FTS3(foobar)' );
|
2011-02-26 16:45:35 +00:00
|
|
|
|
|
|
|
|
$db->duplicateTableStructure( 'foo', 'bar' );
|
2011-04-12 20:48:19 +00:00
|
|
|
$this->assertEquals( 'CREATE VIRTUAL TABLE "bar" USING FTS3(foobar)',
|
2016-02-17 09:09:32 +00:00
|
|
|
$db->selectField( 'sqlite_master', 'sql', [ 'name' => 'bar' ] ),
|
2011-02-26 16:45:35 +00:00
|
|
|
'Duplication of virtual tables'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$db->duplicateTableStructure( 'foo', 'baz', true );
|
2011-04-12 20:48:19 +00:00
|
|
|
$this->assertEquals( 'CREATE VIRTUAL TABLE "baz" USING FTS3(foobar)',
|
2016-02-17 09:09:32 +00:00
|
|
|
$db->selectField( 'sqlite_master', 'sql', [ 'name' => 'baz' ] ),
|
2011-02-26 16:45:35 +00:00
|
|
|
"Can't create temporary virtual tables, should fall back to non-temporary duplication"
|
|
|
|
|
);
|
|
|
|
|
}
|
2010-12-14 16:26:35 +00:00
|
|
|
|
2013-10-18 10:36:09 +00:00
|
|
|
/**
|
2022-05-27 22:27:16 +00:00
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::deleteJoin
|
2013-10-18 10:36:09 +00:00
|
|
|
*/
|
2011-06-18 20:37:02 +00:00
|
|
|
public function testDeleteJoin() {
|
2015-03-07 12:31:08 +00:00
|
|
|
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
|
2011-06-18 20:37:02 +00:00
|
|
|
$db->query( 'CREATE TABLE a (a_1)', __METHOD__ );
|
|
|
|
|
$db->query( 'CREATE TABLE b (b_1, b_2)', __METHOD__ );
|
2016-02-17 09:09:32 +00:00
|
|
|
$db->insert( 'a', [
|
2019-06-05 21:25:46 +00:00
|
|
|
[ 'a_1' => 1 ],
|
|
|
|
|
[ 'a_1' => 2 ],
|
|
|
|
|
[ 'a_1' => 3 ],
|
|
|
|
|
],
|
2011-06-18 20:37:02 +00:00
|
|
|
__METHOD__
|
|
|
|
|
);
|
2016-02-17 09:09:32 +00:00
|
|
|
$db->insert( 'b', [
|
2019-06-05 21:25:46 +00:00
|
|
|
[ 'b_1' => 2, 'b_2' => 'a' ],
|
|
|
|
|
[ 'b_1' => 3, 'b_2' => 'b' ],
|
|
|
|
|
],
|
2011-06-18 20:37:02 +00:00
|
|
|
__METHOD__
|
|
|
|
|
);
|
2016-02-17 09:09:32 +00:00
|
|
|
$db->deleteJoin( 'a', 'b', 'a_1', 'b_1', [ 'b_2' => 'a' ], __METHOD__ );
|
2011-06-18 20:37:02 +00:00
|
|
|
$res = $db->query( "SELECT * FROM a", __METHOD__ );
|
2016-02-17 09:09:32 +00:00
|
|
|
$this->assertResultIs( [
|
2019-06-05 21:25:46 +00:00
|
|
|
[ 'a_1' => 1 ],
|
|
|
|
|
[ 'a_1' => 3 ],
|
|
|
|
|
],
|
2011-06-18 20:37:02 +00:00
|
|
|
$res
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-28 08:38:21 +00:00
|
|
|
/**
|
|
|
|
|
* @coversNothing
|
|
|
|
|
*/
|
2011-05-09 16:41:51 +00:00
|
|
|
public function testEntireSchema() {
|
2010-12-14 16:26:35 +00:00
|
|
|
global $IP;
|
|
|
|
|
|
2022-03-02 21:24:15 +00:00
|
|
|
$result = Sqlite::checkSqlSyntax( "$IP/maintenance/sqlite/tables-generated.sql" );
|
|
|
|
|
|
|
|
|
|
$this->assertTrue( $result, $result );
|
2010-12-14 16:26:35 +00:00
|
|
|
}
|
2011-05-09 16:41:51 +00:00
|
|
|
|
2013-10-18 10:36:09 +00:00
|
|
|
/**
|
2022-05-27 22:27:16 +00:00
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::insertId
|
2013-10-18 10:36:09 +00:00
|
|
|
*/
|
2012-04-06 18:54:24 +00:00
|
|
|
public function testInsertIdType() {
|
2015-03-07 12:31:08 +00:00
|
|
|
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
|
2013-10-18 10:36:09 +00:00
|
|
|
|
|
|
|
|
$databaseCreation = $db->query( 'CREATE TABLE a ( a_1 )', __METHOD__ );
|
2019-11-08 20:15:35 +00:00
|
|
|
$this->assertInstanceOf( ResultWrapper::class, $databaseCreation, "Database creation" );
|
2013-10-18 10:36:09 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$insertion = $db->insert( 'a', [ 'a_1' => 10 ], __METHOD__ );
|
2013-10-18 10:36:09 +00:00
|
|
|
$this->assertTrue( $insertion, "Insertion worked" );
|
|
|
|
|
|
2019-12-13 14:29:10 +00:00
|
|
|
$this->assertIsInt( $db->insertId(), "Actual typecheck" );
|
2012-04-06 18:54:24 +00:00
|
|
|
$this->assertTrue( $db->close(), "closing database" );
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-31 15:32:46 +00:00
|
|
|
/**
|
2022-05-27 22:27:16 +00:00
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::insert
|
2018-10-31 15:32:46 +00:00
|
|
|
*/
|
|
|
|
|
public function testInsertAffectedRows() {
|
|
|
|
|
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
|
|
|
|
|
$db->query( 'CREATE TABLE testInsertAffectedRows ( foo )', __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$insertion = $db->insert(
|
|
|
|
|
'testInsertAffectedRows',
|
|
|
|
|
[
|
|
|
|
|
[ 'foo' => 10 ],
|
|
|
|
|
[ 'foo' => 12 ],
|
|
|
|
|
[ 'foo' => 1555 ],
|
|
|
|
|
],
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
$this->assertTrue( $insertion, "Insertion worked" );
|
|
|
|
|
|
|
|
|
|
$this->assertSame( 3, $db->affectedRows() );
|
|
|
|
|
$this->assertTrue( $db->close(), "closing database" );
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-01 19:59:16 +00:00
|
|
|
/**
|
|
|
|
|
* @coversNothing
|
|
|
|
|
*/
|
2013-10-23 22:51:31 +00:00
|
|
|
public function testCaseInsensitiveLike() {
|
2012-12-24 20:10:22 +00:00
|
|
|
// TODO: Test this for all databases
|
2015-03-07 12:31:08 +00:00
|
|
|
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
|
2013-02-14 13:10:38 +00:00
|
|
|
$res = $db->query( 'SELECT "a" LIKE "A" AS a' );
|
|
|
|
|
$row = $res->fetchRow();
|
|
|
|
|
$this->assertFalse( (bool)$row['a'] );
|
2012-12-24 20:10:22 +00:00
|
|
|
}
|
2014-05-21 11:38:56 +00:00
|
|
|
|
2017-12-28 08:28:45 +00:00
|
|
|
/**
|
|
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::__toString
|
|
|
|
|
*/
|
2015-10-05 20:42:28 +00:00
|
|
|
public function testToString() {
|
|
|
|
|
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
|
|
|
|
|
|
|
|
|
|
$toString = (string)$db;
|
|
|
|
|
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'sqlite object', $toString );
|
2015-10-05 20:42:28 +00:00
|
|
|
}
|
2018-02-28 00:00:05 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::getAttributes()
|
|
|
|
|
*/
|
|
|
|
|
public function testsAttributes() {
|
|
|
|
|
$attributes = Database::attributesFromType( 'sqlite' );
|
|
|
|
|
$this->assertTrue( $attributes[Database::ATTR_DB_LEVEL_LOCKING] );
|
|
|
|
|
}
|
2019-11-08 20:15:35 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::insert()
|
|
|
|
|
* @param string $version
|
|
|
|
|
* @param string $table
|
|
|
|
|
* @param array $rows
|
|
|
|
|
* @param string $expectedSql
|
|
|
|
|
* @dataProvider provideNativeInserts
|
|
|
|
|
*/
|
|
|
|
|
public function testNativeInsertSupport( $version, $table, $rows, $expectedSql ) {
|
|
|
|
|
$sqlDump = '';
|
|
|
|
|
$db = $this->newMockDb( $version, $sqlDump );
|
|
|
|
|
$db->query( 'CREATE TABLE a ( a_1 )', __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$sqlDump = '';
|
|
|
|
|
$db->insert( $table, $rows, __METHOD__ );
|
|
|
|
|
$this->assertEquals( $expectedSql, $sqlDump );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function provideNativeInserts() {
|
|
|
|
|
return [
|
|
|
|
|
[
|
2020-03-18 21:28:32 +00:00
|
|
|
'3.8.0',
|
2019-11-08 20:15:35 +00:00
|
|
|
'a',
|
|
|
|
|
[ 'a_1' => 1 ],
|
2022-09-28 18:32:39 +00:00
|
|
|
'INSERT INTO "a" (a_1) VALUES (1);'
|
2019-11-08 20:15:35 +00:00
|
|
|
],
|
|
|
|
|
[
|
2020-03-18 21:28:32 +00:00
|
|
|
'3.8.0',
|
2019-11-08 20:15:35 +00:00
|
|
|
'a',
|
|
|
|
|
[
|
|
|
|
|
[ 'a_1' => 2 ],
|
|
|
|
|
[ 'a_1' => 3 ]
|
|
|
|
|
],
|
2022-09-28 18:32:39 +00:00
|
|
|
'INSERT INTO "a" (a_1) VALUES (2),(3);'
|
2019-11-08 20:15:35 +00:00
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
2019-11-08 21:52:24 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers \Wikimedia\Rdbms\DatabaseSqlite::replace()
|
|
|
|
|
* @param string $version
|
|
|
|
|
* @param string $table
|
|
|
|
|
* @param array $ukeys
|
|
|
|
|
* @param array $rows
|
|
|
|
|
* @param string $expectedSql
|
|
|
|
|
* @dataProvider provideNativeReplaces
|
|
|
|
|
*/
|
|
|
|
|
public function testNativeReplaceSupport( $version, $table, $ukeys, $rows, $expectedSql ) {
|
|
|
|
|
$sqlDump = '';
|
|
|
|
|
$db = $this->newMockDb( $version, $sqlDump );
|
|
|
|
|
$db->query( 'CREATE TABLE a ( a_1 PRIMARY KEY, a_2 )', __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$sqlDump = '';
|
|
|
|
|
$db->replace( $table, $ukeys, $rows, __METHOD__ );
|
|
|
|
|
$this->assertEquals( $expectedSql, $sqlDump );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function provideNativeReplaces() {
|
|
|
|
|
return [
|
|
|
|
|
[
|
2020-03-18 21:28:32 +00:00
|
|
|
'3.8.0',
|
2019-11-08 21:52:24 +00:00
|
|
|
'a',
|
|
|
|
|
[ 'a_1' ],
|
|
|
|
|
[ 'a_1' => 1, 'a_2' => 'x' ],
|
2022-09-28 18:32:39 +00:00
|
|
|
'REPLACE INTO "a" (a_1,a_2) VALUES (1,\'x\');'
|
2019-11-08 21:52:24 +00:00
|
|
|
],
|
|
|
|
|
[
|
2020-03-18 21:28:32 +00:00
|
|
|
'3.8.0',
|
2019-11-08 21:52:24 +00:00
|
|
|
'a',
|
|
|
|
|
[ 'a_1' ],
|
|
|
|
|
[
|
|
|
|
|
[ 'a_1' => 2, 'a_2' => 'x' ],
|
|
|
|
|
[ 'a_1' => 3, 'a_2' => 'y' ]
|
|
|
|
|
],
|
2022-09-28 18:32:39 +00:00
|
|
|
'REPLACE INTO "a" (a_1,a_2) VALUES (2,\'x\'),(3,\'y\');'
|
2019-11-08 21:52:24 +00:00
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
2011-04-12 20:48:19 +00:00
|
|
|
}
|