Commit graph

63 commits

Author SHA1 Message Date
Umherirrender
c417320dd2 Fix Database::getTempTableWrites for multi table DDLs
Capture group with * does not return a array, only the last match.
Match all and split on the delimiter instead

Bug: T252183
Change-Id: I39701dd367bf2914e7c6fb24b3f14f09a059e483
2020-07-28 17:50:17 +02:00
Thiemo Kreuz
6aa6d10e86 Replace all call_user_func(_array) in all tests
There is native support for all of this now in PHP, thanks to changes
and additions that have been made in later versions. There should be no
need any more to ever use call_user_func() or call_user_func_array().

Reviewing this should be fairly easy: Because this patch touches
exclusivly tests, but no production code, there is no such thing as
"insufficent test coverage". As long as CI goes green, this should be
fine.

Change-Id: Ib9690103687734bb5a85d3dab0e5642a07087bbc
2020-06-06 18:41:20 +02:00
Daimona Eaytoy
2b37cfaf18 build: Bump mediawiki-codesniffer to 31.0.0
Done with `composer fix` and suppressing the rest (i.e. sniffs for
global variables, which for core should be suppressed anyway).

Additionally, add `-p` to `phpcbf`, as otherwise it just seems stuck.

Change-Id: Ide8d6cdd083655891b6d654e78440fbda81ab2bc
2020-05-30 14:56:28 +00:00
Peter Ovchyn
64ea02b060 database: Disallow db->update() without condition
In order to prevent possible performance or replication issues, empty condition
for 'update' queries shouldn't be allowed

Bug: T243619
Depends-On: Ica5f4719c7c927a4e33ba818c40c9f6fc1a5ee7b
Change-Id: Ib728b639ec0c1b079046ac0f8492449def36f2a0
2020-04-29 19:25:27 +03:00
Aaron Schulz
cbc700e186 rbms: optimize and rename truncateTable() to truncate()
Allow truncation of multiple tables. This also provides for
a way to avoid risky keywords like CASCADE for Postgres.

For Postgres, use RESTART IDENTITY, which has been supported
since Postgres 8.4.

Avoid TRUNCATE/DELETE queries for empty temp tables, which is
useful for integrations tests that frequently call this method.

Reorganize and tweak the regexes in Database::getTempWrites().
It now recognizes multi-table DROP/TRUNCATE (Postgres-style).

Change-Id: Idd49f118b20ea5a0f7a3e8c00369aabcd45dd44e
2020-04-21 01:26:18 -07:00
Aaron Schulz
13b11a946e rdbms: reduce duplication in Database via helper methods
Add several new internal methods to help with wrangling
the various formats that rows, conditions, options, and
unique key lists can come in. Remove now unused method
isMultiRowArray().

Add various sanity checks and logging for parameters to
upsert(), replace(), insert(), and insertSelect().

Move DatabasePostgresTest to the integration/ directory.

Change-Id: If5988a6f0816e8da2cbf2fd612e1a3e3a2e9c52f
2020-03-10 22:26:04 +00:00
Aaron Schulz
5d6470d37d rdbms: make Database::build(Greatest|Least) support expressions
This makes it possible to use with counter UPDATE queries.

Also add some extra sanity checks for input types.

Change-Id: Ibc2b7173e28022b5ba7bb04d11c594313a47a101
2020-02-15 21:56:57 +00:00
Tim Starling
d06a3e049b Add SelectQueryBuilder
Add a query builder class which encapsulates the parameters to
IDatabase::select() and related functions.

Override useIndexClause() and ignoreIndexClause() in DatabaseTestHelper
so that index hints can be tested.

Bug: T243051
Change-Id: I58eec4eeb23bd7fb05b8b77d0a748f1026afee52
2020-02-07 10:10:17 +11:00
Tim Starling
00c8a5cbde In Database::select() allow an empty array for $table
Previously it would give FROM followed by nothing which is always a
syntax error. Easier to fix it here than to convert empty arrays to
empty strings in SelectQueryBuilder.

Bug: T243051
Change-Id: I95a9b6a34cfb5c1ca4cf243c4226b5ed4f968035
2020-02-07 09:57:27 +11:00
Aaron Schulz
314efebb56 rdbms: add GREATEST/LEAST wrappers to IDatabase
Change-Id: I9de931123b03ce10713a3a9bbb34e1332dd5965b
2020-01-17 22:19:08 +00:00
James D. Forrester
4f2d1efdda Coding style: Auto-fix MediaWiki.Classes.UnsortedUseStatements.UnsortedUse
Change-Id: I94a0ae83c65e8ee419bbd1ae1e86ab21ed4d8210
2020-01-10 09:32:25 -08:00
Tim Starling
673d496f2d Have Database::addQuotes() pass through bare integers without quoting
Quotes started being added to integers in r4984 (August 2004). Before
that, is_numeric() was used to determine whether to add quotes, so
quotes were omitted from numeric strings, which is obviously wrong.

The idea here is to use the type of the variable to hint to the database
as to whether quotes are needed. The results are somewhat inconsistent,
since some callers do not convert numeric strings obtained from user
input to integers. That makes it a more conservative change. Callers can
opt out of unquoted integers by casting them to string.

The reason for doing this is that quoting integers turns out to be not
as harmless as originally assumed. We found a case of it confusing the
MariaDB query planner, causing inappropriate indexes to be used.

I also made addQuotes() consistently return a string, instead of
returning an integer for boolean values. This was already the case for
MySQL, but it seems like a good idea everywhere.

Bug: T238378
Change-Id: I70473280f542ee5ecd79e187f580807410fbd548
2019-11-18 11:40:28 +11:00
Max Semenik
48a323f702 tests: Add explicit return type void to setUp() and tearDown()
Bug: T192167
Depends-On: I581e54278ac5da3f4e399e33f2c7ad468bae6b43
Change-Id: I3a21fb55db76bac51afdd399cf40ed0760e4f343
2019-10-30 14:31:22 -07:00
James D. Forrester
83d76f4cb5 phpcs: Enable MediaWiki.Commenting.PhpunitAnnotations.ForbiddenExpectedException* and make pass
Change-Id: I63f97497714a32236268be6965c5e181dade6c58
2019-10-14 12:48:48 -07:00
Max Semenik
bc3878e33a Begin cleaning up PHPUnit 4 code from tests
This process will be broken up into several parts for reviewability.

Bug: T192167
Change-Id: Ie415fd3308384a5ca2b3de24ba037785f8a3a714
2019-10-04 14:19:05 -07:00
Thiemo Kreuz
32a429e8c4 tests: Prefer assertSame() when comparing the integer 0
assertSame() is guaranteed to not do any type conversion. This can be
critical when acciden tially comparing, for example, 0 to 0.0.

Change-Id: Iffcc9bda69573623ba14af655dcd697d0fcce525
2019-09-19 15:35:23 +00:00
Aaron Schulz
1fbb16c712 rdbms: expand on LoadBalancer ownership concept
Enforce this pattern for the remaining LoadBalancer methods.
Carry this over into Database::close() to decide how loud the
error handling should be.

In LBFactory, clean up ownership of newMainLB()/newExternalLB().
The should have a null owner if called from outside the class
since the LBFactory does not track nor care about them anymore
in that case. Disable newMainLB() for LBFactorySingle as it
makes no sense and was broken.

Also remove some redundant abstract LBFactory methods that
just duplciate ILBFactory.

Bug: T231443
Bug: T217819
Depends-On: I7ed5c799320430c196a9a8e81af901999e2de7d0
Change-Id: I90b30a79754cfcc290277d302052e60df4fbc649
2019-09-05 12:08:13 -07:00
Aaron Schulz
04d591935c rdbms: normalize Database/LBFactory logging and add snapshot flushing warnings
Make flushSnapshot() logging more detailed and check for explicit transaction
rounds. Also removing periods and trailing newlines from log/exception messages.

Change-Id: I0f6520f563680ab3a65b6338ced59ba25a2ec7b5
2019-07-06 13:10:24 -07:00
Aaron Schulz
1b031cbf3f rdbms: make temp table tracking in Database more robust
Do not register table changes until query success

Change-Id: I8c0eeb510d15e2f4cc014f62b7a0f146e31b6613
2019-07-04 13:36:30 +00:00
Brad Jorsch
f8b48c99bf rdbms: Add callback for atomic section cancellation
The callback will be called immediately when the section is cancelled,
whether that occurs directly, or via cancelling of an outer section, or
via rollback of the entire transaction.

Change-Id: Id05296948b52b95544547bd38c4387496b6c83b9
2019-06-27 20:09:42 -07:00
Legoktm
4e35134f7a Revert "Separate MediaWiki unit and integration tests"
This reverts commit 0a2b996278.

Reason for revert: Broke postgres tests.

Change-Id: I27d8e0c807ad5f0748b9611a4f3df84cc213fbe1
2019-06-13 23:00:08 +00:00
Máté Szabó
0a2b996278 Separate MediaWiki unit and integration tests
This changeset implements T89432 and related tickets and is based on exploration
done at the Prague Hackathon. The goal is to identify tests in MediaWiki core
that can be run without having to install & configure MediaWiki and its dependencies,
and provide a way to execute these tests via the standard phpunit entry point,
allowing for faster development and integration with existing tooling like IDEs.

The initial set of tests that met these criteria were identified using the work Amir did in
I88822667693d9e00ac3d4639c87bc24e5083e5e8. These tests were then moved into a new subdirectory
under phpunit/ and organized into a separate test suite. The environment for this suite
is set up via a PHPUnit bootstrap file without a custom entry point.

You can execute these tests by running:
$ vendor/bin/phpunit -d memory_limit=512M -c tests/phpunit/unit-tests.xml

Bug: T89432
Bug: T87781
Bug: T84948
Change-Id: Iad01033a0548afd4d2a6f2c1ef6fcc9debf72c0d
2019-06-13 22:56:31 +02:00
Aaron Schulz
2866c9b7d4 rdbms: add Database::executeQuery() method for internal use
This shares reconnection and retry logic but lacks some of the
restrictions applied to queries that go through the public query()
interface.

Use this in a few places such as doSelectDomain() for mysql/mssql.

Bug: T212284
Change-Id: Ie7341a0e6c4149fc375cc357877486efe9e56eb9
2019-06-11 14:00:41 +00:00
Aaron Schulz
108fd8b18c rdbms: treat cloned temporary tables as "effective write" targets
Make IDatabase::lastDoneWrites() reflect creation and changes to
the cloned temporary unit test tables but not other temporary tables.
This effects the LB method hasOrMadeRecentMasterChanges(). Other tables
are assumpted to really just be there for temporary calculations rather
acting as test-only ephemeral versions of permanent tables. Treating
writes to the "fake permanent" temp tables more like real permanent
tables means that the tests better align with production.

At the moment, temporary tables still have to use DB_MASTER, given
the assertIsWritableMaster() check in query(). This restriction
can be lifted at some point, when RDBMs compatibility is robust.

Bug: T218388
Change-Id: I4c0d629da254ac2aaf31aae35bd2efc7bc064ac6
2019-03-26 14:24:42 -07:00
Fomafix
204126e7c7 Simplify strings in PHP code
Change-Id: I481810ade68b0c5a5be21d22e2a107646d5813e6
2019-03-01 22:16:26 +01:00
Fomafix
cff7dac346 Fix @param tags
* Use 'callable' instead of 'callback'.
* Remove '$' as part of a type name.
* Add missing type.

Change-Id: Ic1b39a7d8cbbee000d8fb2f3a1f71a621bd01993
2019-02-03 16:49:10 +01:00
Umherirrender
fc19d2ab03 Add missing @covers to database related tests
Change-Id: I370275bb6c5d456b73f6a5f782e231f16c2b0fbe
2019-02-01 20:43:02 +00:00
Brad Jorsch
c5a5b02240 Database: Allow selectFieldValues() to accept SQL fragments
The documentation says "This must be a valid SQL fragment", but as
written it breaks if given anything other than a field name. It's easy
enough to fix by adding an alias to the internal select() call.

Bug: T201781
Change-Id: I76428af6d3aadc266254fdb24109a0ac2db3761f
2018-10-17 22:21:40 +00:00
Brad Jorsch
bf30fcb714 Database: close() should not commit transactions
Transactional databases normally roll back when a connection is closed
with an open transaction rather than committing them, so MediaWiki
committing them is unexpected.

There are two cases being changed here: automatic transactions without
writes and manual transactions. For the former it shouldn't make a
difference if we commit or roll back since no writes were done anyway.
The latter has logged a message since MW 1.31 (I0992f9a8), and that
warning has not been logged in Wikimedia production in the past 60 days
so we should be ok there too.

Bug: T206147
Change-Id: Ieceef4deb49044db8f0622d38ee76c9d9f39704c
2018-10-03 14:55:43 -04:00
Aaron Schulz
46cf714ce7 rdbms: make * consistently act like in select/insertSelect methods
This now matches the documentation of insertSelect()

Bug: T202553
Change-Id: Ie6602fdd3b48b9136de7c65289c85ced5f5f2f1d
2018-10-01 14:31:53 -07:00
Aaron Schulz
9eff263e8e rdbms: add IDatabase::lockForUpdate() convenience method
Change-Id: I238fd96407e1122e90058e2c4acf743044a267ec
2018-07-10 20:09:01 +01:00
Bartosz Dziewoński
485f66f174 Use PHP 7 '??' operator instead of '?:' with 'isset()' where convenient
Find: /isset\(\s*([^()]+?)\s*\)\s*\?\s*\1\s*:\s*/
Replace with: '\1 ?? '

(Everywhere except includes/PHPVersionCheck.php)
(Then, manually fix some line length and indentation issues)

Then manually reviewed the replacements for cases where confusing
operator precedence would result in incorrect results
(fixing those in I478db046a1cc162c6767003ce45c9b56270f3372).

Change-Id: I33b421c8cb11cdd4ce896488c9ff5313f03a38cf
2018-05-30 18:06:13 -07:00
Aaron Schulz
0b5ed025e9 rdbms: do not silently rollback empty transactions on error
Since there might be important view snapshots, temp tables, or effects
from SET statements or the like, go into TRX_ERROR state for "possible
transaction level errors" even if no recognized writes took place and
the transaction was not explicit.

Change-Id: I32c34bc28b845e343d0167a220412824838eaed8
2018-05-30 03:10:02 +00:00
Aaron Schulz
b6cd5421b9 rdbms: rename onTransactionIdle() to onTransactionCommitOrIdle()
This is clearer and is consistent with onTransactionPreCommitOrIdle()

Change-Id: I3a34a0e9adea69ec55ed6ddfef47703e31e7c3b5
2018-05-09 21:07:06 +00:00
Aaron Schulz
c8085ad43f rdbms: make IDatabase::onTransaction* methods pass the DB handle for convenience
Change-Id: Ia45a26830d62326b103593268fbf34c907783c90
2018-04-24 16:45:11 -07:00
jenkins-bot
984381d6d9 Merge "rdbms: make select() warn when FOR UPDATE is used with aggregation" 2018-04-23 20:01:13 +00:00
Aaron Schulz
b992b3aea5 rdbms: make select() warn when FOR UPDATE is used with aggregation
Using FOR UPDATE or LOCK IN SHARE MODE with aggregation leads to
query errors with PostgreSQL.

Bug: T160910
Change-Id: Iaed964e7e59468365cbc62cb4bfd3ad44b898452
2018-04-20 03:42:26 +00:00
Aaron Schulz
20777d7399 rdbms: make cancelAtomic() handle callbacks and work with DBO_TRX
Make transaction callbacks aware of cancelled sections. If the
statements of a section are reverted via cancelAtomic(), then the
dependant callbacks are now cancelled as well. Any callbacks for
onTransactionResolution(), which does not depend on COMMIT, will
see the triggering event as a ROLLBACK, since the unit of work it
was part of was rolled back.

Also fix the handling of topmost atomic sections with DBO_TRX.
These still need their own savepoint to make cancelAtomic() work.

Follow-up to 52aeaa7a5.

Change-Id: If4d455c98155283797678cfb9df31d5317dd91a2
2018-04-19 12:43:01 -07:00
jenkins-bot
2d030f4576 Merge "rdbms: allow cancelation of dangling nested atomic sections" 2018-04-11 19:48:00 +00:00
Aaron Schulz
f9d10f9e03 rdbms: fix transaction flushing in Database::close
Use the right IDatabase constants for the $flush parameter to
the commit() and rollback() calls.

This fixes a regression from 3975e04cf4.

Also validate the mode/flush parameters to begin() and commit().

Bug: T191916
Change-Id: I0992f9a87f2add303ed309efcc1adb781baecfdc
2018-04-10 22:31:31 -07:00
Aaron Schulz
477b835945 rdbms: allow cancelation of dangling nested atomic sections
* Make startAtomic() return a token that can be used with cancelAtomic()
  cancel any nested atomic sections that have not yet been ended.
* Make doAtomicSection() clear dangling nested sections by default.
* Also give doAtomicSection() a $cancelable parameter, having the
  same default as startAtomic().

Change-Id: I75fa234cb1dcfef17dc9a973a3b02d2607efa98e
2018-04-10 16:34:31 -07:00
Brad Jorsch
0618227f7f rdbms: Issue a deprecation warning if errors are ignored
I532bc5201 added code to put the Database into an error state on error,
to prevent callers from catching and ignoring exceptions without rolling
back. But to avoid breaking everything relying on the ability to do so,
it didn't set the error state for certain types of errors.

To allow those broken callers to be cleaned up, log a deprecation
warning when we detect that someone has indeed ignored one of these
errors.

Bug: T189999
Change-Id: Ib7aca59639f30959e106fd4f1a1209e28bad2857
2018-04-10 02:06:44 +00:00
Kunal Mehta
b4925e34d0 tests: Enable PHPUnit 4/6 compat layer in some tests that need it
Change-Id: I27a21fa9e97414fae02acbefb28011f0275cba63
2018-04-07 19:31:24 -07:00
Brad Jorsch
395462b7d5 rdbms: Roll back empty implicit transaction on error
If we're not going to set trxStatus to an error state in this case, we
need to issue a rollback to be sure the database (i.e. PostgreSQL) isn't
still in an error state too.

Bug: T189999
Change-Id: Id6e203b216fff937b6a97d779b36c278e3366409
2018-04-05 14:45:18 -04:00
Aaron Schulz
3975e04cf4 rdbms: make Database query error handling more strict
Handle all errors in query() that might have caused rollback by
putting the Database handle into an error state that can only be
resolved by cancelAtomic() or rollback(). Other queries will be
rejected until then.

This results in more immediate exceptions in some cases where
atomic section mismatch errors would have been thrown, such as a
an error bubbling up from a child atomic section. Most cases were
a try/catch block assumes that only the statement was rolled back
now result in an error and rollback.

Callers using try/catch to handle key conflicts should instead use
SELECT FOR UPDATE to find conflicts beforehand, or use IGNORE, or
the upsert()/replace() methods. The try/catch pattern is unsafe and
no longer allowed, except for some common errors known to just
rollback the statement. Even then, such statements can come from
child atomic sections, so committing would be unsafe. Luckily, in
such cases, there will be a mismatch detected on endAtomic() or a
dangling section detected in close(), resulting in rollback.

Remove caching from DatabaseMyslBase::getServerVariableSettings
in case some SET query changes the values.

Bug: T189999
Change-Id: I532bc5201681a915d0c8aa7a3b1c143b040b142e
2018-04-04 21:26:11 -07:00
Brad Jorsch
3365e83d96 rdbms: Add ATOMIC_CANCELABLE flag for micro-optimization
Aaron is concerned about the extra time added to atomic sections within
an outer transaction if we do a SAVEPOINT and RELEASE. He wants a flag
so callers have to specifically opt-in to use of savepoints.

Change-Id: I64cf5033ced464863d28dd49d9173856a9c1e1c0
2018-03-22 07:20:54 +00:00
Brad Jorsch
52aeaa7a5f rdbms: Add IDatabase::cancelAtomic()
Atomic sections are currently useful if you want to wrap some SQL
statements in a transaction when you might be called from inside someone
else's transaction, and you expect the caller to roll back everything if
you fail.

But there are some cases where you want to allow the caller to recover
from errors, in which case you need to roll back just the atomic
section. Savepoints are supported by all our databases and can be used
for this purpose, so let's do so.

Bug: T188660
Change-Id: Iee548619df89fd7fbd581b01106b8b41d3df71cc
2018-03-22 05:57:42 +00:00
Aaron Schulz
d395dfb039 rdbms: make selectRowCount() use $var argument to exclude NULLs
If the $var argument is provided, then it will make the resulting
count exclude rows where the value for that column is NULL.

Also add buildSelectSubquery() method and Subquery
wrapper class for use with select() for calculated tables.

Change-Id: I549d629af99afdf370602de095f7fba6d1546c37
2018-03-18 01:34:33 +00:00
Brad Jorsch
83731192b2 Remove useless use
A use declaration for a non-namespaced class in a non-namespaced context
causes a PHP warning.

Bug: T189302
Change-Id: I023e64c8194dd03cc3a1098e2d60c73f99bb02e3
2018-03-09 14:11:36 -05:00
addshore
0526f2d671 Introduce IDatabase::buildIntegerCast
Change-Id: Ib24856d1ebe017ff07ae497972c764b4a3f3c7df
2018-03-07 13:00:18 +00:00