Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F5982204
DatabaseMysqlTest.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
DatabaseMysqlTest.php
View Options
<?php
use
MediaWiki\MediaWikiServices
;
use
Wikimedia\Rdbms\ChangedTablesTracker
;
use
Wikimedia\Rdbms\DatabaseMySQL
;
use
Wikimedia\Rdbms\DBError
;
use
Wikimedia\Rdbms\DBQueryDisconnectedError
;
use
Wikimedia\Rdbms\DBQueryError
;
use
Wikimedia\Rdbms\DBQueryTimeoutError
;
use
Wikimedia\Rdbms\DBSessionStateError
;
use
Wikimedia\Rdbms\DBTransactionStateError
;
use
Wikimedia\Rdbms\DBUnexpectedError
;
use
Wikimedia\Rdbms\IDatabase
;
use
Wikimedia\Rdbms\Platform\ISQLPlatform
;
use
Wikimedia\Rdbms\Platform\SQLPlatform
;
use
Wikimedia\Rdbms\Query
;
use
Wikimedia\Rdbms\TransactionManager
;
/**
* @covers \Wikimedia\Rdbms\Database
* @covers \Wikimedia\Rdbms\DatabaseMySQL
* @covers \Wikimedia\Rdbms\Platform\MySQLPlatform
* @group mysql
* @group Database
* @group medium
* @requires extension mysqli
*/
class
DatabaseMysqlTest
extends
\MediaWikiIntegrationTestCase
{
/** @var DatabaseMySQL */
protected
$conn
;
protected
function
setUp
():
void
{
parent
::
setUp
();
$lb
=
MediaWikiServices
::
getInstance
()->
getDBLoadBalancer
();
if
(
$lb
->
getServerType
(
0
)
!==
'mysql'
)
{
$this
->
markTestSkipped
(
'No MySQL $wgLBFactoryConf config detected'
);
}
$this
->
conn
=
$this
->
newConnection
();
// FIXME: Tables used by this test aren't parsed correctly, see T344510.
ChangedTablesTracker
::
stopTracking
();
}
protected
function
tearDown
():
void
{
if
(
$this
->
conn
)
{
$this
->
conn
->
close
(
__METHOD__
);
ChangedTablesTracker
::
startTracking
();
}
parent
::
tearDown
();
}
public
function
testQueryTimeout
()
{
try
{
$res
=
$this
->
conn
->
query
(
'SET STATEMENT max_statement_time=0.001 FOR SELECT sleep(1) FROM dual'
,
__METHOD__
);
// if the query did not time out, there should be a single row where sleep() returned 1
$this
->
assertSame
(
1
,
$res
->
numRows
()
);
$row
=
$res
->
fetchRow
();
$this
->
assertSame
(
'1'
,
(
string
)
reset
(
$row
)
);
}
catch
(
DBQueryTimeoutError
$e
)
{
$this
->
assertInstanceOf
(
DBQueryTimeoutError
::
class
,
$e
);
}
$row
=
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
assertSame
(
'x'
,
$row
->
v
,
"Still connected/usable"
);
}
public
function
testConnectionKill
()
{
try
{
$this
->
conn
->
query
(
'KILL (SELECT connection_id())'
,
__METHOD__
);
$this
->
fail
(
"No DBQueryDisconnectedError caught"
);
}
catch
(
DBQueryDisconnectedError
$e
)
{
$this
->
assertInstanceOf
(
DBQueryDisconnectedError
::
class
,
$e
);
}
$row
=
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
assertSame
(
'x'
,
$row
->
v
,
"Recovered"
);
}
public
function
testConnectionLossQuery
()
{
$row
=
$this
->
conn
->
query
(
'SELECT connection_id() AS id'
,
__METHOD__
)->
fetchObject
();
$encId
=
intval
(
$row
->
id
);
$adminConn
=
$this
->
newConnection
();
$adminConn
->
query
(
"KILL $encId"
,
__METHOD__
);
$row
=
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
assertSame
(
'x'
,
$row
->
v
,
"Recovered"
);
$this
->
conn
->
startAtomic
(
__METHOD__
);
$this
->
assertSame
(
1
,
$this
->
conn
->
trxLevel
(),
"Transaction exists"
);
$row
=
$this
->
conn
->
query
(
'SELECT connection_id() AS id'
,
__METHOD__
)->
fetchObject
();
$encId
=
intval
(
$row
->
id
);
$adminConn
->
query
(
"KILL $encId"
,
__METHOD__
);
try
{
$this
->
conn
->
query
(
'SELECT 1'
,
__METHOD__
);
$this
->
fail
(
"No DBQueryDisconnectedError caught"
);
}
catch
(
DBQueryDisconnectedError
$e
)
{
$this
->
assertTrue
(
$this
->
conn
->
isOpen
(),
"Reconnected"
);
try
{
$this
->
conn
->
endAtomic
(
__METHOD__
);
$this
->
fail
(
"No DBUnexpectedError caught"
);
}
catch
(
DBUnexpectedError
$e
)
{
$this
->
assertInstanceOf
(
DBUnexpectedError
::
class
,
$e
);
}
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_ERROR
,
$this
->
conn
->
trxStatus
()
);
try
{
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
fail
(
"No DBTransactionStateError caught"
);
}
catch
(
DBTransactionStateError
$e
)
{
$this
->
assertInstanceOf
(
DBTransactionStateError
::
class
,
$e
);
}
$this
->
assertSame
(
0
,
$this
->
conn
->
trxLevel
(),
"Transaction lost"
);
$this
->
conn
->
rollback
(
__METHOD__
);
$this
->
assertSame
(
0
,
$this
->
conn
->
trxLevel
(),
"No transaction"
);
$row
=
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
assertSame
(
'x'
,
$row
->
v
,
"Recovered"
);
}
$this
->
conn
->
lock
(
'session_lock_'
.
mt_rand
(),
__METHOD__
,
0
);
$row
=
$this
->
conn
->
query
(
'SELECT connection_id() AS id'
,
__METHOD__
)->
fetchObject
();
$encId
=
intval
(
$row
->
id
);
$adminConn
->
query
(
"KILL $encId"
,
__METHOD__
);
try
{
$this
->
conn
->
query
(
'SELECT 1'
,
__METHOD__
);
$this
->
fail
(
"No DBQueryDisconnectedError caught"
);
}
catch
(
DBQueryDisconnectedError
$e
)
{
$this
->
assertInstanceOf
(
DBQueryDisconnectedError
::
class
,
$e
);
}
$this
->
assertTrue
(
$this
->
conn
->
isOpen
(),
"Reconnected"
);
try
{
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
fail
(
"No DBSessionStateError caught"
);
}
catch
(
DBSessionStateError
$e
)
{
$this
->
assertInstanceOf
(
DBSessionStateError
::
class
,
$e
);
}
$this
->
assertTrue
(
$this
->
conn
->
isOpen
(),
"Connection remains"
);
$this
->
conn
->
rollback
(
__METHOD__
);
$this
->
conn
->
flushSession
(
__METHOD__
);
$row
=
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
assertSame
(
'x'
,
$row
->
v
,
"Recovered"
);
$adminConn
->
close
(
__METHOD__
);
}
public
function
testConnectionLossSnapshotFlush
()
{
$fakeWriteQuery
=
new
Query
(
'SELECT 1'
,
SQLPlatform
::
QUERY_CHANGE_ROWS
,
'SELECT'
);
$this
->
conn
->
begin
(
__METHOD__
,
IDatabase
::
TRANSACTION_INTERNAL
);
$row
=
$this
->
conn
->
query
(
'SELECT connection_id() AS id'
,
__METHOD__
)->
fetchObject
();
$encId
=
intval
(
$row
->
id
);
$adminConn
=
$this
->
newConnection
();
$adminConn
->
query
(
"KILL $encId"
,
__METHOD__
);
$this
->
conn
->
flushSnapshot
(
__METHOD__
);
$this
->
assertSame
(
0
,
$this
->
conn
->
trxLevel
(),
"Lost connection during snapshot flush"
);
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_NONE
,
$this
->
conn
->
trxStatus
()
);
$this
->
conn
->
begin
(
__METHOD__
,
IDatabase
::
TRANSACTION_INTERNAL
);
$this
->
conn
->
query
(
$fakeWriteQuery
,
__METHOD__
);
$row
=
$this
->
conn
->
query
(
'SELECT connection_id() AS id'
,
__METHOD__
)->
fetchObject
();
$encId
=
intval
(
$row
->
id
);
$adminConn
->
query
(
"KILL $encId"
,
__METHOD__
);
try
{
$this
->
conn
->
query
(
$fakeWriteQuery
,
__METHOD__
);
$this
->
fail
(
"Error thrown due to connection loss with pending writes"
);
}
catch
(
DBError
$e
)
{
$this
->
assertInstanceOf
(
DBQueryDisconnectedError
::
class
,
$e
);
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_ERROR
,
$this
->
conn
->
trxStatus
()
);
}
try
{
$this
->
conn
->
query
(
'SELECT 1'
,
__METHOD__
);
$this
->
fail
(
"Error thrown due to unacknowledged transaction error"
);
}
catch
(
DBError
$e
)
{
$this
->
assertInstanceOf
(
DBTransactionStateError
::
class
,
$e
);
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_ERROR
,
$this
->
conn
->
trxStatus
()
);
}
$this
->
conn
->
flushSnapshot
(
__METHOD__
);
$this
->
assertSame
(
0
,
$this
->
conn
->
trxLevel
(),
"Snapshot flush after lost writes"
);
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_NONE
,
$this
->
conn
->
trxStatus
()
);
// Get a lock outside of any transaction
$unlocker
=
$this
->
conn
->
getScopedLockAndFlush
(
'testing-key'
,
__METHOD__
,
0
);
// Start transaction after getting the lock
$this
->
conn
->
begin
(
__METHOD__
,
IDatabase
::
TRANSACTION_INTERNAL
);
$row
=
$this
->
conn
->
query
(
'SELECT connection_id() AS id'
,
__METHOD__
)->
fetchObject
();
$encId
=
intval
(
$row
->
id
);
$adminConn
->
query
(
"KILL $encId"
,
__METHOD__
);
try
{
$this
->
conn
->
query
(
'SELECT 1'
,
__METHOD__
);
$this
->
fail
(
"Error thrown due to connection loss with locks"
);
}
catch
(
DBError
$e
)
{
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_ERROR
,
$this
->
conn
->
trxStatus
()
);
}
$this
->
conn
->
flushSnapshot
(
__METHOD__
);
$this
->
assertSame
(
0
,
$this
->
conn
->
trxLevel
(),
"Snapshot flush with lost lock"
);
try
{
$this
->
conn
->
query
(
'SELECT 1'
,
__METHOD__
);
$this
->
fail
(
"Error thrown due to unacknowledged session error"
);
}
catch
(
DBError
$e
)
{
$this
->
assertInstanceOf
(
DBSessionStateError
::
class
,
$e
);
}
$adminConn
->
close
(
__METHOD__
);
}
public
function
testConnectionLossScopedLock
()
{
$row
=
$this
->
conn
->
query
(
'SELECT connection_id() AS id'
,
__METHOD__
)->
fetchObject
();
$encId
=
intval
(
$row
->
id
);
try
{
(
function
()
use
(
$encId
)
{
$unlocker
=
$this
->
conn
->
getScopedLockAndFlush
(
'x'
,
'fn'
,
1
);
$adminConn
=
$this
->
newConnection
();
$adminConn
->
query
(
"KILL $encId"
);
$this
->
conn
->
query
(
"SELECT 1"
);
}
)();
$this
->
fail
(
"Expected DBQueryDisconnectedError"
);
}
catch
(
DBQueryDisconnectedError
$e
)
{
// This should report the explicit query that failed,
// instead of the (later) implicit query from the $unlocker deref.
$this
->
assertStringContainsString
(
"SELECT 1"
,
$e
->
getMessage
()
);
}
$this
->
conn
->
rollback
(
__METHOD__
);
$this
->
conn
->
unlock
(
'x'
,
__METHOD__
);
}
public
function
testTransactionError
()
{
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_NONE
,
$this
->
conn
->
trxStatus
()
);
$this
->
conn
->
startAtomic
(
__METHOD__
,
IDatabase
::
ATOMIC_CANCELABLE
);
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_OK
,
$this
->
conn
->
trxStatus
()
);
$row
=
$this
->
conn
->
query
(
'SELECT connection_id() AS id'
,
__METHOD__
)->
fetchObject
();
$encId
=
intval
(
$row
->
id
);
try
{
$this
->
conn
->
lock
(
'trx_lock_'
.
mt_rand
(),
__METHOD__
,
0
);
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_OK
,
$this
->
conn
->
trxStatus
()
);
$this
->
conn
->
query
(
"SELECT invalid query()"
,
__METHOD__
);
$this
->
fail
(
"No DBQueryError caught"
);
}
catch
(
DBQueryError
$e
)
{
$this
->
assertInstanceOf
(
DBQueryError
::
class
,
$e
);
}
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_ERROR
,
$this
->
conn
->
trxStatus
()
);
try
{
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
fail
(
"No DBTransactionStateError caught"
);
}
catch
(
DBTransactionStateError
$e
)
{
$this
->
assertInstanceOf
(
DBTransactionStateError
::
class
,
$e
);
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_ERROR
,
$this
->
conn
->
trxStatus
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
trxLevel
(),
"Transaction remains"
);
$this
->
assertTrue
(
$this
->
conn
->
isOpen
(),
"Connection remains"
);
}
$adminConn
=
$this
->
newConnection
();
$adminConn
->
query
(
"KILL $encId"
,
__METHOD__
);
$this
->
assertSame
(
TransactionManager
::
STATUS_TRX_ERROR
,
$this
->
conn
->
trxStatus
()
);
try
{
$this
->
conn
->
query
(
'SELECT 1'
,
__METHOD__
);
$this
->
fail
(
"No DBTransactionStateError caught"
);
}
catch
(
DBTransactionStateError
$e
)
{
$this
->
assertInstanceOf
(
DBTransactionStateError
::
class
,
$e
);
}
$this
->
assertSame
(
1
,
$this
->
conn
->
trxLevel
(),
"Transaction loss not yet detected (due to STATUS_TRX_ERROR)"
);
$this
->
assertTrue
(
$this
->
conn
->
isOpen
(),
"Connection loss not detected (due to STATUS_TRX_ERROR)"
);
$this
->
conn
->
cancelAtomic
(
__METHOD__
);
$this
->
assertSame
(
0
,
$this
->
conn
->
trxLevel
(),
"No transaction remains"
);
$this
->
assertTrue
(
$this
->
conn
->
isOpen
(),
"Reconnected"
);
$row
=
$this
->
conn
->
query
(
'SELECT "x" AS v'
,
__METHOD__
)->
fetchObject
();
$this
->
assertSame
(
'x'
,
$row
->
v
,
"Recovered"
);
$this
->
conn
->
rollback
(
__METHOD__
);
$adminConn
->
close
(
__METHOD__
);
}
private
function
newConnection
():
DatabaseMySQL
{
$lb
=
MediaWikiServices
::
getInstance
()->
getDBLoadBalancer
();
$dbFactory
=
MediaWikiServices
::
getInstance
()->
getDatabaseFactory
();
/** @var DatabaseMySQL $conn */
$conn
=
$dbFactory
->
create
(
'mysql'
,
array_merge
(
$lb
->
getServerInfo
(
0
),
[
'dbname'
=>
null
,
'schema'
=>
null
,
'tablePrefix'
=>
''
,
]
)
);
return
$conn
;
}
public
function
testInsertIdAfterInsert
()
{
$dTable
=
$this
->
createDestTable
();
$rows
=
[
[
'k'
=>
'Luca'
,
'v'
=>
mt_rand
(
1
,
100
),
't'
=>
time
()
]
];
$this
->
conn
->
insert
(
$dTable
,
$rows
,
__METHOD__
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
0
,
$this
->
conn
->
insertId
()
);
$this
->
dropDestTable
();
}
public
function
testInsertIdAfterInsertIgnore
()
{
$dTable
=
$this
->
createDestTable
();
$rows
=
[
[
'k'
=>
'Luca'
,
'v'
=>
mt_rand
(
1
,
100
),
't'
=>
time
()
]
];
$this
->
conn
->
insert
(
$dTable
,
$rows
,
__METHOD__
,
'IGNORE'
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
conn
->
insert
(
$dTable
,
$rows
,
__METHOD__
,
'IGNORE'
);
$this
->
assertSame
(
0
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
0
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
0
,
$this
->
conn
->
insertId
()
);
$this
->
dropDestTable
();
}
public
function
testInsertIdAfterReplace
()
{
$dTable
=
$this
->
createDestTable
();
$rows
=
[
[
'k'
=>
'Luca'
,
'v'
=>
mt_rand
(
1
,
100
),
't'
=>
time
()
]
];
$this
->
conn
->
replace
(
$dTable
,
'k'
,
$rows
,
__METHOD__
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
conn
->
replace
(
$dTable
,
'k'
,
$rows
,
__METHOD__
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
2
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
2
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
0
,
$this
->
conn
->
insertId
()
);
$this
->
dropDestTable
();
}
public
function
testInsertIdAfterUpsert
()
{
$dTable
=
$this
->
createDestTable
();
$rows
=
[
[
'k'
=>
'Luca'
,
'v'
=>
mt_rand
(
1
,
100
),
't'
=>
time
()
]
];
$set
=
[
'v = '
.
$this
->
conn
->
buildExcludedValue
(
'v'
),
't = '
.
$this
->
conn
->
buildExcludedValue
(
't'
)
.
' + 1'
];
$this
->
conn
->
upsert
(
$dTable
,
$rows
,
'k'
,
$set
,
__METHOD__
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
conn
->
upsert
(
$dTable
,
$rows
,
'k'
,
$set
,
__METHOD__
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
0
,
$this
->
conn
->
insertId
()
);
$this
->
dropDestTable
();
}
public
function
testInsertIdAfterInsertSelect
()
{
$sTable
=
$this
->
createSourceTable
();
$dTable
=
$this
->
createDestTable
();
$rows
=
[
[
'sk'
=>
'Luca'
,
'sv'
=>
mt_rand
(
1
,
100
),
'st'
=>
time
()
]
];
$this
->
conn
->
insert
(
$sTable
,
$rows
,
__METHOD__
,
'IGNORE'
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$sTable
,
'sn'
,
[
'sk'
=>
'Luca'
]
)
);
$this
->
conn
->
insertSelect
(
$dTable
,
$sTable
,
[
'k'
=>
'sk'
,
'v'
=>
'sv'
,
't'
=>
'st'
],
[
'sk'
=>
'Luca'
],
__METHOD__
,
'IGNORE'
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
0
,
$this
->
conn
->
insertId
()
);
$this
->
dropSourceTable
();
$this
->
dropDestTable
();
}
public
function
testInsertIdAfterInsertSelectIgnore
()
{
$sTable
=
$this
->
createSourceTable
();
$dTable
=
$this
->
createDestTable
();
$rows
=
[
[
'sk'
=>
'Luca'
,
'sv'
=>
mt_rand
(
1
,
100
),
'st'
=>
time
()
]
];
$this
->
conn
->
insert
(
$sTable
,
$rows
,
__METHOD__
,
'IGNORE'
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$sTable
,
'sn'
,
[
'sk'
=>
'Luca'
]
)
);
$this
->
conn
->
insertSelect
(
$dTable
,
$sTable
,
[
'k'
=>
'sk'
,
'v'
=>
'sv'
,
't'
=>
'st'
],
[
'sk'
=>
'Luca'
],
__METHOD__
,
'IGNORE'
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
1
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
conn
->
insertSelect
(
$dTable
,
$sTable
,
[
'k'
=>
'sk'
,
'v'
=>
'sv'
,
't'
=>
'st'
],
[
'sk'
=>
'Luca'
],
__METHOD__
,
'IGNORE'
);
$this
->
assertSame
(
0
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
0
,
$this
->
conn
->
insertId
()
);
$this
->
assertSame
(
1
,
(
int
)
$this
->
conn
->
selectField
(
$dTable
,
'n'
,
[
'k'
=>
'Luca'
]
)
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
()
);
$this
->
assertSame
(
0
,
$this
->
conn
->
insertId
()
);
$this
->
dropSourceTable
();
$this
->
dropDestTable
();
}
/**
* @coversNothing
*/
public
function
testAffectedRowsAfterUpdateIgnore
()
{
$sTable
=
$this
->
createSourceTable
();
$rows
=
[
[
'sk'
=>
'Luca'
,
'sv'
=>
mt_rand
(
1
,
100
),
'st'
=>
time
()
],
[
'sk'
=>
'Test'
,
'sv'
=>
mt_rand
(
1
,
100
),
'st'
=>
time
()
]
];
$this
->
conn
->
insert
(
$sTable
,
$rows
,
__METHOD__
,
'IGNORE'
);
$this
->
assertSame
(
2
,
$this
->
conn
->
affectedRows
(),
'Test inserted'
);
// Test changing something
$this
->
conn
->
update
(
$sTable
,
[
'sk'
=>
'TestRow'
],
[
'sk'
=>
'Test'
],
__METHOD__
,
[
'IGNORE'
]
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
(),
'Updated'
);
// Test changing nothing
$this
->
conn
->
update
(
$sTable
,
[
'sk'
=>
'TestRow'
],
[
'sk'
=>
'TestRow'
],
__METHOD__
,
[
'IGNORE'
]
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
(),
'Nothing changed'
);
// Test nothing found
$this
->
conn
->
update
(
$sTable
,
[
'sk'
=>
'TestExistingRow'
],
[
'sk'
=>
'TestNonexistingRow'
],
__METHOD__
,
[
'IGNORE'
]
);
$this
->
assertSame
(
0
,
$this
->
conn
->
affectedRows
(),
'Not found'
);
// Test key conflict on the unique sk field
$this
->
conn
->
update
(
$sTable
,
[
'sk'
=>
'TestRow'
],
[
'sk'
=>
'Luca'
],
__METHOD__
,
[
'IGNORE'
]
);
$this
->
assertSame
(
1
,
$this
->
conn
->
affectedRows
(),
'Key conflict, nothing changed on database'
);
}
public
function
testFieldAndIndexInfo
()
{
global
$wgDBname
;
$this
->
conn
->
selectDomain
(
$wgDBname
);
$this
->
conn
->
query
(
"CREATE TEMPORARY TABLE tmp_schema_tbl ("
.
"n integer not null auto_increment, "
.
"k varchar(255), "
.
"v integer, "
.
"t integer,"
.
"PRIMARY KEY (n),"
.
"UNIQUE INDEX k (k),"
.
"INDEX t (t)"
.
")"
);
$this
->
assertTrue
(
$this
->
conn
->
fieldExists
(
'tmp_schema_tbl'
,
'n'
)
);
$this
->
assertTrue
(
$this
->
conn
->
fieldExists
(
'tmp_schema_tbl'
,
'k'
)
);
$this
->
assertTrue
(
$this
->
conn
->
fieldExists
(
'tmp_schema_tbl'
,
'v'
)
);
$this
->
assertTrue
(
$this
->
conn
->
fieldExists
(
'tmp_schema_tbl'
,
't'
)
);
$this
->
assertFalse
(
$this
->
conn
->
fieldExists
(
'tmp_schema_tbl'
,
'x'
)
);
$this
->
assertTrue
(
$this
->
conn
->
indexExists
(
'tmp_schema_tbl'
,
'k'
)
);
$this
->
assertTrue
(
$this
->
conn
->
indexExists
(
'tmp_schema_tbl'
,
't'
)
);
$this
->
assertFalse
(
$this
->
conn
->
indexExists
(
'tmp_schema_tbl'
,
'x'
)
);
$this
->
assertTrue
(
$this
->
conn
->
indexExists
(
'tmp_schema_tbl'
,
'PRIMARY'
)
);
$this
->
assertTrue
(
$this
->
conn
->
indexUnique
(
'tmp_schema_tbl'
,
'k'
)
);
$this
->
assertFalse
(
$this
->
conn
->
indexUnique
(
'tmp_schema_tbl'
,
't'
)
);
$this
->
assertNull
(
$this
->
conn
->
indexUnique
(
'tmp_schema_tbl'
,
'x'
)
);
$this
->
assertTrue
(
$this
->
conn
->
indexUnique
(
'tmp_schema_tbl'
,
'PRIMARY'
)
);
}
private
function
createSourceTable
()
{
global
$wgDBname
;
$this
->
conn
->
query
(
"DROP TABLE IF EXISTS `$wgDBname`.`tmp_src_tbl`"
);
$this
->
conn
->
query
(
"CREATE TEMPORARY TABLE `$wgDBname`.`tmp_src_tbl` ("
.
"sn integer not null unique key auto_increment, "
.
"sk varchar(255) unique, "
.
"sv integer, "
.
"st integer"
.
")"
);
return
"$wgDBname.tmp_src_tbl"
;
}
private
function
createDestTable
()
{
global
$wgDBname
;
$this
->
conn
->
query
(
"DROP TABLE IF EXISTS `$wgDBname`.`tmp_dst_tbl`"
);
$this
->
conn
->
query
(
"CREATE TEMPORARY TABLE `$wgDBname`.`tmp_dst_tbl` ("
.
"n integer not null unique key auto_increment, "
.
"k varchar(255) unique, "
.
"v integer, "
.
"t integer"
.
")"
);
return
"$wgDBname.tmp_dst_tbl"
;
}
private
function
dropSourceTable
()
{
global
$wgDBname
;
$this
->
conn
->
query
(
"DROP TEMPORARY TABLE IF EXISTS `$wgDBname`.`tmp_src_tbl`"
);
}
private
function
dropDestTable
()
{
global
$wgDBname
;
$this
->
conn
->
query
(
"DROP TEMPORARY TABLE IF EXISTS `$wgDBname`.`tmp_dst_tbl`"
);
}
/**
* Insert a null value into a field that is not nullable using INSERT IGNORE
*/
public
function
testInsertIgnoreNull
()
{
$this
->
expectException
(
DBQueryError
::
class
);
$this
->
conn
->
newInsertQueryBuilder
()
->
insertInto
(
'log_search'
)
->
ignore
()
->
row
(
[
'ls_field'
=>
'test'
,
'ls_value'
=>
null
,
'ls_log_id'
=>
1
]
)
->
execute
();
}
/**
* @covers \Wikimedia\Rdbms\DatabaseMySQL::query
* @covers \Wikimedia\Rdbms\DatabaseMySQL::dropTable
*/
public
function
testTempTableDomains
()
{
global
$wgDBname
;
$table
=
'temp_test_tbl'
;
$this
->
conn
->
selectDomain
(
$wgDBname
.
'-xxx1_'
);
$this
->
assertFalse
(
$this
->
conn
->
tableExists
(
$table
)
);
$query
=
new
Query
(
"CREATE TEMPORARY TABLE "
.
$this
->
conn
->
tableName
(
$table
)
.
" (n integer not null unique key)"
,
ISQLPlatform
::
QUERY_CHANGE_SCHEMA
,
"CREATE TEMPORARY"
,
$table
);
$this
->
conn
->
query
(
$query
,
__METHOD__
);
$this
->
assertTrue
(
$this
->
conn
->
tableExists
(
$table
)
);
$this
->
conn
->
selectDomain
(
$wgDBname
.
'-xxx2_'
);
$this
->
assertFalse
(
$this
->
conn
->
tableExists
(
$table
)
);
$query
=
new
Query
(
"CREATE TEMPORARY TABLE "
.
$this
->
conn
->
tableName
(
$table
)
.
" (n integer not null unique key)"
,
ISQLPlatform
::
QUERY_CHANGE_SCHEMA
,
"CREATE TEMPORARY"
,
$table
);
$this
->
conn
->
query
(
$query
,
__METHOD__
);
$this
->
assertTrue
(
$this
->
conn
->
tableExists
(
$table
)
);
$this
->
conn
->
selectDomain
(
$wgDBname
.
'-xxx1_'
);
$this
->
conn
->
dropTable
(
$table
);
$this
->
assertFalse
(
$this
->
conn
->
tableExists
(
$table
)
);
$this
->
conn
->
selectDomain
(
$wgDBname
.
'-xxx2_'
);
$this
->
conn
->
dropTable
(
$table
);
$this
->
assertFalse
(
$this
->
conn
->
tableExists
(
$table
)
);
}
/**
* @covers \Wikimedia\Rdbms\DatabaseMySQL::query
* @covers \Wikimedia\Rdbms\DatabaseMySQL::dropTable
*/
public
function
testTempTableDomainsTableWithDot
()
{
global
$wgDBname
;
$table
=
'.temp_test_tbl'
;
$this
->
conn
->
selectDomain
(
$wgDBname
.
'-xxx1_'
);
$this
->
assertFalse
(
$this
->
conn
->
tableExists
(
$table
)
);
$query
=
new
Query
(
"CREATE TEMPORARY TABLE "
.
$this
->
conn
->
tableName
(
$table
)
.
" (n integer not null unique key)"
,
ISQLPlatform
::
QUERY_CHANGE_SCHEMA
,
"CREATE TEMPORARY"
,
$table
);
$this
->
conn
->
query
(
$query
,
__METHOD__
);
$this
->
assertTrue
(
$this
->
conn
->
tableExists
(
$table
)
);
$this
->
conn
->
selectDomain
(
$wgDBname
.
'-xxx2_'
);
$this
->
assertTrue
(
$this
->
conn
->
tableExists
(
$table
)
);
$this
->
conn
->
dropTable
(
$table
);
$this
->
assertFalse
(
$this
->
conn
->
tableExists
(
$table
)
);
$this
->
conn
->
selectDomain
(
$wgDBname
.
'-xxx1_'
);
$this
->
assertFalse
(
$this
->
conn
->
tableExists
(
$table
)
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, Oct 3, 22:14 (1 w, 3 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
fc/00/00f229c3779be6a2f2f4cedad49c
Default Alt Text
DatabaseMysqlTest.php (23 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment