wiki.techinc.nl/tests/phpunit/includes/libs/rdbms/querybuilder/SelectQueryBuilderTest.php
Reedy 229b2c15e8 Fix a plethora of class and function call case mismatches
Bug: T231412
Change-Id: I597a25de3294a6673424f30475760280ef209a8a
2020-05-26 14:14:46 +01:00

563 lines
13 KiB
PHP

<?php
use Wikimedia\Rdbms\IResultWrapper;
use Wikimedia\Rdbms\SelectQueryBuilder;
/**
* @covers \Wikimedia\Rdbms\SelectQueryBuilder
* @covers \Wikimedia\Rdbms\JoinGroup
* @covers \Wikimedia\Rdbms\BuilderSubquery
*/
class SelectQueryBuilderTest extends PHPUnit\Framework\TestCase {
/** @var DatabaseTestHelper */
private $db;
/** @var SelectQueryBuilder */
private $sqb;
protected function setUp() : void {
$this->db = new DatabaseTestHelper( __CLASS__ . '::' . $this->getName() );
$this->sqb = $this->db->newSelectQueryBuilder();
}
private function assertSQL( $expected ) {
$actual = $this->sqb->getSQL();
$actual = preg_replace( '/ +/', ' ', $actual );
$actual = preg_replace( '/ +$/', '', $actual );
$this->assertEquals( $expected, $actual );
}
public function testNoTable() {
$this->sqb
->select( '1' );
$this->assertSQL( 'SELECT 1' );
}
public function testCondsEtc() {
$this->sqb
->table( 'a' )
->where( '1' )
->andWhere( '2' )
->conds( '3' )
->field( 'f' );
$this->assertSQL( 'SELECT f FROM a WHERE (1) AND (2) AND (3)' );
}
public function testTableAlias() {
$this->sqb
->table( 't', 'a' )
->field( 'f' );
$this->assertSQL( 'SELECT f FROM t a' );
}
public function testTableIndex() {
$this->sqb
->table( 't', null )
->useIndex( 'i' )
->field( 'f' );
$this->assertSQL( 'SELECT f FROM t FORCE INDEX (i)' );
}
public function testTableAliasIndex() {
$this->sqb
->table( 't', 'a' )
->useIndex( 'i' )
->field( 'f' );
$this->assertSQL( 'SELECT f FROM t a FORCE INDEX (i)' );
}
public function testIgnoreIndex() {
$this->sqb
->table( 't' )
->ignoreIndex( 'i' )
->field( 'f' );
$this->assertSQL( 'SELECT f FROM t IGNORE INDEX (i)' );
}
public function testSubquery() {
$this->sqb
->table(
$this->sqb->newSubquery()
->field( 'f' )
->from( 't' )
->useIndex( 'i' ),
'sq'
)
->field( 'sq.f' );
$this->assertSQL( 'SELECT sq.f FROM (SELECT f FROM t FORCE INDEX (i) ) sq' );
}
public function testTablesFields() {
$this->sqb
->tables( [ 'a' => 'b', 'c' ] )
->useIndex( 'ic' )
->useIndex( [ 'a' => 'ia' ] )
->fields( [ 'a', 'b' ] );
$this->assertSQL( 'SELECT a,b FROM b a FORCE INDEX (ia),c FORCE INDEX (ic)' );
}
public function testRawTables() {
$this->sqb
->select( 'f' )
->rawTables( [ 'a' => [ 't1', 't2' ] ] );
$this->assertSQL( "SELECT f FROM (t1,t2 )" );
}
public function testJoin() {
$this->sqb
->table( 'a' )
->join( 'b', 'b', 'aa=bb' )
->field( '*' );
$this->assertSQL( 'SELECT * FROM a JOIN b ON ((aa=bb))' );
}
public function testLeftJoin() {
$this->sqb
->table( 'a' )
->leftJoin( 'b', 'b', 'aa=bb' )
->fields( '*' );
$this->assertSQL( 'SELECT * FROM a LEFT JOIN b ON ((aa=bb))' );
}
public function testAutoAliasedJoin() {
$this->sqb
->table( 'a' )
->join( 'b' )
->field( '*' );
$this->assertSQL( 'SELECT * FROM a JOIN b' );
}
public function testAutoAliasedLeftJoin() {
$this->sqb
->table( 'a' )
->leftJoin( 'b', null, 'aa=bb' )
->field( '*' );
$this->assertSQL( 'SELECT * FROM a LEFT JOIN b ON ((aa=bb))' );
}
public function testLeftJoinGroup() {
$this->sqb
->table( 'a' )
->field( 'f' )
->leftJoin(
$this->sqb->newJoinGroup()
->table( 'b' )
->leftJoin( 'c', 'c', 'bb=cc' ),
null,
'bb=aa'
);
$this->assertSQL( 'SELECT f FROM a LEFT JOIN (b LEFT JOIN c ON ((bb=cc))) ON ((bb=aa))' );
}
public function testInnerJoinGroup() {
$this->sqb
->table( 'a' )
->field( 'f' )
->join(
$this->sqb->newJoinGroup()
->table( 'b' )
->join( 'c', 'c', 'bb=cc' ),
null,
'bb=aa'
);
$this->assertSQL( 'SELECT f FROM a JOIN (b JOIN c ON ((bb=cc))) ON ((bb=aa))' );
}
public function testDoubleJoinGroup() {
$this->sqb
->table( 'a' )
->field( 'f' )
->join(
$this->sqb->newJoinGroup()
->table( 'b' )
->join(
$this->sqb->newJoinGroup()
->table( 'c' )
->join( 'd', 'd', [] ),
null, [] ),
null,
[]
);
$this->assertSQL( 'SELECT f FROM a JOIN (b JOIN (c JOIN d))' );
}
public function testInitialJoinGroup() {
$this->sqb
->table(
$this->sqb->newJoinGroup()
->table( 'a' )
->table( 'b' )
)
->field( 'f' );
$this->assertSQL( 'SELECT f FROM (a,b )' );
}
public function testInitialDoubleJoinGroup() {
$this->sqb
->table( $this->sqb->newJoinGroup()
->table(
$this->sqb->newJoinGroup()
->table( 'a' )
->table( 'b' )
)
->table(
$this->sqb->newJoinGroup()
->table( 'c' )
->table( 'd' )
)
)
->field( 'f' );
$this->assertSQL( 'SELECT f FROM ((a,b ),(c,d ) )' );
}
public function testDegenerateJoinGroup() {
$this->sqb
->table( $this->sqb->newJoinGroup()->table( 'a' ) )
->field( 'f' );
$this->assertSQL( 'SELECT f FROM a' );
}
public function testSubqueryInJoinGroup() {
$this->sqb
->field( 'f' )
->table(
$this->sqb->newJoinGroup()
->table( 'a' )
->join( $this->sqb->newSubquery()->select( '1' ) )
);
$this->assertSQL( 'SELECT f FROM (a,(SELECT 1 ) sqb1_0 )' );
}
public function testConditionsOnGroup() {
$this->sqb
->field( 'f' )
->table( 'a' )
->join(
$this->sqb->newJoinGroup()
->table( 'b' )
->table( 'c' ),
null,
'aa=bb' );
$this->assertSQL( 'SELECT f FROM a JOIN (b,c ) ON ((aa=bb))' );
}
public function testJoinToEmpty() {
$this->expectException( LogicException::class );
$this->sqb->join( 'a', 'a', [] );
}
public function testJoinToEmptyInJoinGroup() {
$this->expectException( LogicException::class );
$this->sqb->newJoinGroup()->join( 'a', 'a', [] );
}
public function testConflictingAlias() {
$this->expectException( LogicException::class );
$this->sqb
->table( 'a' )
->join( 'b' )
->join( 'b' );
}
public function testConflictingAliasInGroup() {
$this->expectException( LogicException::class );
$this->sqb->newJoinGroup()
->table( 'a' )
->join( 'b' )
->join( 'b' );
}
public function testJoinConds() {
$this->sqb
->field( '*' )
->tables( [ 'a', 'b' => 'b' ] )
->joinConds( [ 'b' => [ 'LEFT JOIN', 'aa=bb' ] ] );
$this->assertSQL( 'SELECT * FROM a LEFT JOIN b ON ((aa=bb))' );
}
public function testJoinSubquery() {
$this->sqb
->select( 'sq.a' )
->from( 't1' )
->join(
$this->sqb->newSubquery()->select( 'a' )->from( 't2' ),
'sq',
[]
);
$this->assertSQL( 'SELECT sq.a FROM t1 JOIN (SELECT a FROM t2 ) sq' );
}
public function testLeftJoinSubquery() {
$this->sqb
->select( 'sq.a' )
->from( 't1' )
->leftJoin(
$this->sqb->newSubquery()->select( 'a' )->from( 't2' ),
'sq',
[ 'aa' => null ]
);
$this->assertSQL( 'SELECT sq.a FROM t1 LEFT JOIN (SELECT a FROM t2 ) sq ON (aa IS NULL)' );
}
public function testOffsetLimit() {
$this->sqb
->select( 'f' )
->from( 't' )
->offset( 1 )
->limit( 2 );
$this->assertSQL( 'SELECT f FROM t LIMIT 1,2' );
}
public function testLockInShareMode() {
$this->sqb
->select( 'f' )
->from( 't' )
->lockInShareMode();
$this->assertSQL( 'SELECT f FROM t LOCK IN SHARE MODE' );
}
public function testForUpdate() {
$this->sqb
->select( 'f' )
->from( 't' )
->forUpdate();
$this->assertSQL( 'SELECT f FROM t FOR UPDATE' );
}
public function testDistinct() {
$this->sqb
->select( 'f' )
->from( 't' )
->distinct();
$this->assertSQL( 'SELECT DISTINCT f FROM t' );
}
public function testGroupBy() {
$this->sqb
->select( 'f' )
->from( 't' )
->groupBy( [ '1', '2' ] );
$this->assertSQL( 'SELECT f FROM t GROUP BY 1,2' );
}
public function testHaving() {
$this->sqb
->select( 'f' )
->from( 't' )
->having( [ 'a' => 1 ] );
$this->assertSQL( 'SELECT f FROM t HAVING a = 1' );
}
public function testOrderBy1() {
$this->sqb
->select( [ 'a', 'b', 'c' ] )
->from( 't' )
->orderBy( 'a' )
->orderBy( 'b', 'DESC' )
->orderBy( 'c' );
$this->assertSQL( 'SELECT a,b,c FROM t ORDER BY a,b DESC,c' );
}
public function testOrderBy2() {
$this->sqb
->select( [ 'a', 'b', 'c' ] )
->from( 't' )
->orderBy( [ 'a', 'b', 'c' ] );
$this->assertSQL( 'SELECT a,b,c FROM t ORDER BY a,b,c' );
}
public function testOrderBy3() {
$this->sqb
->select( [ 'a', 'b', 'c' ] )
->from( 't' )
->orderBy( [ 'a', 'b', 'c' ], 'DESC' );
$this->assertSQL( 'SELECT a,b,c FROM t ORDER BY a DESC,b DESC,c DESC' );
}
public function testOrderBy4() {
$this->sqb
->select( [ 'a', 'b', 'c' ] )
->from( 't' )
->orderBy( 'a' )
->orderBy( [ 'b', 'c' ] );
$this->assertSQL( 'SELECT a,b,c FROM t ORDER BY a,b,c' );
}
public function testOrderBy5() {
$this->sqb
->select( [ 'a', 'b', 'c' ] )
->from( 't' )
->option( 'ORDER BY', 'a' )
->orderBy( [ 'b', 'c' ] );
$this->assertSQL( 'SELECT a,b,c FROM t ORDER BY a,b,c' );
}
public function testExplain() {
$this->sqb
->explain()
->select( '*' )
->from( 't' );
$this->assertSQL( 'EXPLAIN SELECT * FROM t' );
}
public function testStraightJoin() {
$this->sqb
->straightJoin()
->select( '1' )
->from( 't' );
$this->assertSQL( 'SELECT /*! STRAIGHT_JOIN */ 1 FROM t' );
}
public function testBigResult() {
$this->sqb
->bigResult()
->select( '1' )
->from( 't' );
$this->assertSQL( 'SELECT SQL_BIG_RESULT 1 FROM t' );
}
public function testSmallResult() {
$this->sqb
->smallResult()
->select( '1' )
->from( 't' );
$this->assertSQL( 'SELECT SQL_SMALL_RESULT 1 FROM t' );
}
public function testCalcFoundRows() {
$this->sqb
->calcFoundRows()
->select( '1' )
->from( 't' );
$this->assertSQL( 'SELECT SQL_CALC_FOUND_ROWS 1 FROM t' );
}
public function testOption() {
$this->sqb
->select( 'f' )
->from( 't' )
->option( 'ORDER BY', 'a' );
$this->assertSQL( 'SELECT f FROM t ORDER BY a' );
}
public function testOptions() {
$this->sqb
->select( '1' )
->options( [ 'ORDER BY' => '1', 'GROUP BY' => '2' ] );
$this->assertSQL( 'SELECT 1 GROUP BY 2 ORDER BY 1' );
}
public function testFetchResultSet() {
$this->sqb->select( '1' )->caller( __METHOD__ );
$res = $this->sqb->fetchResultSet();
$this->assertEquals( 'SELECT 1', $this->db->getLastSqls() );
$this->assertInstanceOf( IResultWrapper::class, $res );
}
public function testFetchField() {
$this->sqb->select( '1' )->caller( __METHOD__ );
$this->sqb->fetchField();
$this->assertEquals( 'SELECT 1 LIMIT 1', $this->db->getLastSqls() );
}
public function testFetchFieldValues() {
$this->sqb->select( '1' )->caller( __METHOD__ );
$res = $this->sqb->fetchFieldValues();
$this->assertEquals( 'SELECT 1 AS value', $this->db->getLastSqls() );
$this->assertIsArray( $res );
}
public function testFetchRow() {
$this->sqb->select( '1' )->caller( __METHOD__ );
$this->sqb->fetchRow();
$this->assertEquals( 'SELECT 1 LIMIT 1', $this->db->getLastSqls() );
}
public function testFetchRowCount() {
$this->sqb->table( 't' )->caller( __METHOD__ );
$this->sqb->fetchRowCount();
$this->assertEquals( 'SELECT COUNT(*) AS rowcount FROM (SELECT 1 FROM t ) tmp_count',
$this->db->getLastSqls() );
}
public function testFetchRowCountWithField() {
$this->sqb->table( 't' )->field( 'f' )->caller( __METHOD__ );
$this->sqb->fetchRowCount();
// phpcs:ignore Generic.Files.LineLength.TooLong
$this->assertEquals( 'SELECT COUNT(*) AS rowcount FROM (SELECT 1 FROM t WHERE (f IS NOT NULL) ) tmp_count',
$this->db->getLastSqls() );
}
public function testEstimateRowCount() {
$this->sqb
->table( 't' )
->conds( [ 'a' => 'b' ] )
->caller( __METHOD__ );
$this->sqb->estimateRowCount();
$this->assertEquals( 'SELECT COUNT(*) AS rowcount FROM t WHERE a = \'b\'',
$this->db->getLastSqls() );
}
public function testLockForUpdate() {
$this->sqb
->table( 't' )
->conds( [ 'a' => 'b' ] )
->caller( __METHOD__ );
$this->db->begin( __METHOD__ );
$this->sqb->lockForUpdate();
$this->db->rollback( __METHOD__ );
// phpcs:ignore Generic.Files.LineLength.TooLong
$this->assertEquals( 'BEGIN; SELECT COUNT(*) AS rowcount FROM (SELECT 1 FROM t WHERE a = \'b\' FOR UPDATE) tmp_count; ROLLBACK',
$this->db->getLastSqls() );
}
public function testBuildGroupConcatField() {
$this->sqb
->select( 'f' )
->from( 't' )
->caller( __METHOD__ );
$res = $this->sqb->buildGroupConcatField( '|' );
$this->assertEquals( '(SELECT GROUP_CONCAT(f SEPARATOR \'|\') FROM t )',
$res );
}
public function testGetSQL() {
$this->sqb
->select( 'f' )
->from( 't' )
->caller( __METHOD__ );
$res = $this->sqb->getSQL();
$this->assertEquals( 'SELECT f FROM t ', $res );
}
public function testGetQueryInfo() {
$this->sqb
->select( 'f' )
->from( 't' )
->conds( [ 'a' => 'b' ] )
->join( 'u', 'u', 'tt=uu' )
->limit( 1 );
$this->assertEquals(
[
'tables' => [ 't', 'u' => 'u' ],
'fields' => [ 'f' ],
'conds' => [ 'a' => 'b' ],
'options' => [ 'LIMIT' => 1 ],
'join_conds' => [ 'u' => [ 'JOIN', 'tt=uu' ] ]
],
$this->sqb->getQueryInfo() );
}
public function testQueryInfo() {
$this->sqb->queryInfo(
[
'tables' => [ 't', 'u' => 'u' ],
'fields' => [ 'f' ],
'conds' => [ 'a' => 'b' ],
'options' => [ 'LIMIT' => 1 ],
'join_conds' => [ 'u' => [ 'JOIN', 'tt=uu' ] ]
]
);
$this->assertSQL( "SELECT f FROM t JOIN u ON ((tt=uu)) WHERE a = 'b' LIMIT 1" );
}
}