Sqlite used the base implementation of trying a SELECT 1 query and
seeing if it failed. Instead, make it use the sqlite_master table.
Also remove the base version of that method since it would always
cause this problem and all subclasses have proper implementations.
Make LoadBalancerTest::assertWriteAllowed() more explicit and add
more assertions there.
Change-Id: I6c7b0bea8894c45dfe8931748d6687f0e5d1e101
This is a follow-up to Idc3dee3a7fb5ebfaef395754d8859b18f1f8769a
containing some less trivial changes.
Change-Id: Ia7af2c1d000307d43278cde4a246df413d4ef263
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
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
* Handle the case where an onTransaction* callback for one handle
adds more onTransaction* callbacks to a different handle. Instead
of supporting only a short chain of such callbacks, try to resolve
the whole chain by using a loop in LoadBalancer and LBFactory.
* Add sanity checks to enforce the proper call order of LoadBalancer
transaction methods, such as those that execute callbacks. This is
the order that LBFactory already uses. Use ROUND_ERROR for problems
that can ruin the instance state. Such problems require rollback.
* Correct setTrxEndCallbackSuppression() calls in beginMasterChanges()
that were making tests fail.
* Make Database handle callback suppression for FLUSHING_ALL_PEERS
instead of making LoadBalancer/LBFactory have to manage it.
* Simplify finalizeMasterChanges() given that suppression does not
actually effect runOnTransactionPreCommitCallbacks().
* Make dangling callback warning in Database::close work properly.
* Actually use $fname in flushReplicaSnapshots().
* Use DBTransactionError instead of DBExpectedError in some places
where stages fail.
* Fix failing testGetScopedLock() unit tests so everything passes.
Add more comments to setTransactionListener and onTransactionIdle.
Change-Id: I6a25a6e4e5ba666e0da065a24846cbab7e786c7b
Using FOR UPDATE or LOCK IN SHARE MODE with aggregation leads to
query errors with PostgreSQL.
Bug: T160910
Change-Id: Iaed964e7e59468365cbc62cb4bfd3ad44b898452
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
The "AUTO" means AUTOCOMMIT, not "automatic transactions"/DBO_TRX,
which is basically the opposite concept. The new name does not
suffer from that ambiguity.
Keep the old constant as an alias for backwards compatibility.
Also remove LoadBalancer comment about non-existing field
Change-Id: I63beeb061fc9be73f320308e4d6393b58628b8c8
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
* 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
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
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
If it is known that master writes will use GTIDs with a certain
domain and server ID, ignore other ones on masterPosWait().
This restores ceb7d61ee except it uses the same server variables
and MySQLMasterPos preserves the active server/domain information
across serialization.
Change-Id: I1a4f143adcbec642966d7d1a55edb0f414a7f0c4
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
* Make onTransactionIdle() wait until any transaction round
is gone, even if there is no SQL transaction active. This
is what onTransactionPreCommitOrIdle() already does.
* Decouple "transaction round mode" (DBO_TRX) from whether a
round is active via a 'trxRoundId' LB info field. If rounds
are enabled, but not is started, then the transaction state
should be interpreted as "idle".
* Improve related documentation.
* Add more related unit tests.
Change-Id: I3ab18f577ec0375897fcb63f18f4ee2deeb436e9
* Filter out GTIDs with a domain that is not the one binlog
events would be written to if the Database handle was given
write queries. Likewise for the MariaDB server_id component.
* Also improve MySQL GTID support to better match that of MariaDB.
This covers position retrieval, replication waiting, and ranges
in GTIDs (which are almost always present).
* Make some MySQLMasterPos variables private by making use of
accesors instead.
* Store the gtids array keyed by domain ID for convenience.
* Clean up dynamic call to static method.
Change-Id: Ic6ab517bc8f200c968ff892ade69ad1b9394ab21
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
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
* Make sure cancelled onTransactionPreCommitOrIdle() callbacks do not
run if a transaction round is rolled back and then a second round is
committed. LoadBalancer::rollbackMasterChanges() now always calls
rollback(), which in turn always cleans up such callbacks.
* Remove error logging for rollback() calls when trxLevel = 0; this is
harmless and is sometimes hard to avoid in error handling anyway.
* Add more related unit tests.
Change-Id: I6bdefe8bf8b6630fc252b5bbafe4808758ba1684
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
A use declaration for a non-namespaced class in a non-namespaced context
causes a PHP warning.
Bug: T189302
Change-Id: I023e64c8194dd03cc3a1098e2d60c73f99bb02e3
* Database::factory() supports a $connect parameter, that defaults
to NEW_CONNECTED (current behavior) but can also be NEW_UNCONNECTED.
* Add tests asserting the type of various instances returned from
Database::factory().
* Clean up sqlite "conn" field handling to handle cases of it
not being set, just as other classes do.
* Add some comments about the return type of doQuery().
Change-Id: Ic0837cfdb35326c2045133d664abd29043d48c03
Follows-up b4eb1feed0, which inadvertendly replaced the setFlag()
test with the clearFlag() test.
Also move the test to the DatabaseTest.php file given it's only
executing and covering base class.
Change-Id: I2f4ed6c4eeba845eb67013e1ab7d2b2bde863119
This fixes an issue that arises because empty( "0" ) is true in PHP.
The new behavior rejects any conditions that are not strings or arrays,
and lets $conds = "0" be passed to the databases as WHERE 0.
Some databases may reject this as invalid syntax, which is the expected
behavior here, instead of silently ignoring the 0, causing no condition to
be applied to the query.
Bug: T188314
Change-Id: I5bc4d7f41221a886c85e54d9da67c4c095a7d9ce
An INSERT SELECT in MySQL/MariaDB is unsafe for replication if a column
is getting values from auto-increment, statement-based replication is in
use, and the default innodb_autoinc_lock_mode is set.
I9173f655 added checks to force non-native insertSelect for the
statement-based replication and innodb_autoinc_lock_mode != 2 case, but
determining whether a column is getting values from auto-increment is
too hard to do automatically there.
Instead, let's add a flag to let the caller hint that the query isn't
getting any auto-increment values. And use it in MysqlUpdater when
appropriate.
Bug: T160993
Change-Id: If70450a64aa3bcbf763c62838bb21306d124ae3d
It would be easy for a call to nonNativeInsertSelect() to generate an
INSERT that's too big for the database to actually process. Add batching
to try to avoid that.
Bug: T160993
Change-Id: I1de994208d95926f0d75c0d7cab7b5fe1dd565c3