Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRM-20445 Add dispatcher to modifyQuery #180

Merged
merged 1 commit into from
Jul 9, 2019

Conversation

eileenmcnaughton
Copy link
Contributor

@eileenmcnaughton eileenmcnaughton commented Apr 11, 2017

This allows a query to be modified from an extension - e.g by prepending data like '/* Query run by user 45*/'

@totten this is working for me now....

@eileenmcnaughton eileenmcnaughton changed the title [WIP] Add dispatcher to modifyQuery CRM-20445 Add dispatcher to modifyQuery Apr 19, 2017
@seamuslee001
Copy link
Contributor

Jenkins test this pelase

@davejenx
Copy link

Hi @eileenmcnaughton, hope you're enjoying sunny Manchester!
Had a little look at this PR on the way back - just a few thoughts for now in lieu of actual testing...

  1. Can a Symfony-style hook be used in a unit test, in order to test this PR?

  2. Does it work if the hook injects a comment that has whitespace before the /* ? I think the check in DB::isManip() may not catch this, so the comment wouldn't be removed, so the function would return false. I haven't checked this or traced through to see what consequence that would have.

  3. Does it allow through /* ... */ in quoted strings, e.g.

INSERT INTO civicrm_activity(..., details, ...)
VALUES (..., "Learnt that in MySQL, inline comments can be added /* like this */.", ...)
``` ?

@seamuslee001
Copy link
Contributor

@eileenmcnaughton any thoughts on where to take this?

@eileenmcnaughton
Copy link
Contributor Author

@seamuslee001 I guess the above is basically - 'needs test'

@eileenmcnaughton
Copy link
Contributor Author

And finally civicrm/civicrm-core#14716

eileenmcnaughton added a commit to eileenmcnaughton/civicrm-core that referenced this pull request Jul 3, 2019
@eileenmcnaughton
Copy link
Contributor Author

test this please

eileenmcnaughton added a commit to eileenmcnaughton/civicrm-core that referenced this pull request Jul 3, 2019
The performance of TRUNCATE is slower than DELETE FROM.

Probably due to

Note that this provides a way to stop hacking core
civicrm/civicrm-packages#180
eileenmcnaughton added a commit to eileenmcnaughton/civicrm-packages that referenced this pull request Jul 3, 2019
@davejenx
Copy link

davejenx commented Jul 9, 2019

Hi @eileenmcnaughton,

Have tested this successfully.

  • General standards
    • Explain (r-explain)
      • SOFT PASS : The goal/problem/solution have been briefly explained with a link. An improvement would be to link to extension code that demonstrates its use and briefly describe the usage, e.g. the string added to the query must begin with /* with no leading whitespace, must be a valid MySQL comment and end with */. The added comment will appear in MySQL process list & query log but not in Civi query log.
    • User impact (r-user)
      • PASS: The change would be intuitive or unnoticeable for a majority of users who work with this feature.
    • Documentation (r-doc)
    • Run it (r-run)
      • PASS: after applying the patch, I installed org.wikimedia.userquerydata . Initially I tested be enabling CIVICRM_DEBUG_LOG_QUERY, however the added comment did not appear there. I then tested by repeatedly checking MySQL process list, where I did see the added comment. Also tested creating an activity with details text containing a MySQL comment, to make sure this wasn't broken by the change - all OK.
  • Developer standards
    • Technical impact (r-tech)
      • PASS: I gather from comments that Tim was involved in formulating the approach, so if he's OK with it I'll go with... The change preserves compatibility with existing callers/code/downstream.
    • Code quality (r-code)
      • PASS: The functionality, purpose, and style of the code seems clear+sensible.
    • Maintainability (r-maint)
    • Test results (r-test)
      • UNREVIEWED
      • COMMENTS: haven't yet run the associated test.

@eileenmcnaughton
Copy link
Contributor Author

Great @davejenx I'll merge this & re-run the test on master. I'll also comment the documentation issue on the test

@eileenmcnaughton eileenmcnaughton merged commit 94b3028 into civicrm:master Jul 9, 2019

if (class_exists('Civi\Core\Container') && \Civi\Core\Container::isContainerBooted()) {
Civi\Core\Container::singleton()->get('dispatcher')->dispatch('civi.db.query',
\Civi\Core\Event\GenericHookEvent::create(array('query' => &$query))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileenmcnaughton Regarding performance, the dispatch() should be pretty cheap on non-hook events.

Since this isn't actually a hook, and since we're likely to fire O(100)s of times, I'd lean pretty solidly against using GenericHookEvent for this. Instead, make a class that doesn't use any reflection or array-mangling, like:

namespace Civi\Core\Event;

/**
 * Class QueryEvent
 * @package Civi\Event
 */
class QueryEvent extends \Symfony\Component\EventDispatcher\Event {

  /**
   * @var string
   */
  public $query;

  /**
   * QueryEvent constructor.
   * @param string $query
   */
  public function __construct($query) {
    $this->query = $query;
  }

}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@totten lol - that was code you proposed in an earlier conversation - but OK - I think I see what you say we should change it to - let me try

totten added a commit to totten/civicrm-core that referenced this pull request Jul 25, 2019
Overview
--------

The recently merged PR for CRM-20455, civicrm/civicrm-packages#180, uses the
GenericHookEvent for modifying all SQL queries.  GHE is flexible, but it
comes with a slight performance penalty (juggling a few internal arrays).
The penalty is usually too small to care if you're firing one hook. However, with CRM-20455,
we can foresee the event firing hundreds or even thousands of times within a given page-view.

This PR adds a smaller/simpler class for use with `modifyQuery`. There will be a different PR to use it.

Before
------

* Don't have `QueryEvent`

After
-----

* Do have `QueryEvent`
totten added a commit to totten/civicrm-packages that referenced this pull request Jul 25, 2019
Overview
--------

The recently merged PR civicrm#180 added `modifyQuery()` to allow dynamic
inspection/modification of most SQL queries (*post-boot*).

This patch modifies and micro-optimizes the new (unreleased) interface.

Ordinarily, one wouldn't care about this level of micro-optimization;
however, it's entirely foreseeable that this code will run hundreds or even
thousands of times while a user works with a single page.

Before
------

For each typical SQL query, the call to `modifyQuery()` requires:

* Constructing an instance of `GenericHookEvent`, which does some
  array shuffling and encourages reflective code.
* Performing multiple lookups of the container/dispatcher system

After
-----

For each typical SQL query, the call to `modifyQuery()` requires:

* Constructing an instance of `QueryEvent`, which is a lighter object
* Fewer lookups (`isset(Civi::$static[...])`)

Comments
--------

I did some simple benchmarks -- running 10,000 simple SQL queries with
various forms of `modifyQuery()`.  The baseline (no events) had the fastest
average (`9.444`s).  Adding GHE bumped runtime up +9% (`10.298`s).  With
this patch, it only adds +3.5% (`9.787`s).

The averages are based on 5 samples each.  For full details, see
https://gist.github.com/totten/da21a8386a7ddcc62def5d78e912bf8c
eileenmcnaughton added a commit to eileenmcnaughton/civicrm-core that referenced this pull request Aug 27, 2019
The performance of TRUNCATE is slower than DELETE FROM.

Probably due to

Note that this provides a way to stop hacking core
civicrm/civicrm-packages#180
wmfgerrit pushed a commit to wikimedia/wikimedia-fundraising-crm that referenced this pull request Sep 6, 2019
For years we carried a hack to track the user behind any run-away queries. An alternative
(suggested by Tim) that I put up a long time back has finally been merged
and this utilises that approach - allowing us to drop another patch.  Our  other
patch in the packages directory was merged for 5.18 so this is the last time
we should need to patch  packages

civicrm/civicrm-packages#180

I did some performance tests & while I found the starting point (~460 per minute) seemed slower than when I last did
some tests I got a little better with the 5.17 upgrade (~484 per minute) & no discernable difference when
switching to this approach. Note that the 460 per minute could reflect 'something' going on so there is not
necessarily an improvement with the 5.17 update but not worse is also good.

Bug: T228826

Change-Id: Ib9074b982dd43c706dd08bf577e81bd72335024f
eileenmcnaughton added a commit to eileenmcnaughton/civicrm-core that referenced this pull request Jan 7, 2020
The performance of TRUNCATE is slower than DELETE FROM.

Probably due to

Note that this provides a way to stop hacking core
civicrm/civicrm-packages#180
eileenmcnaughton added a commit to eileenmcnaughton/civicrm-core that referenced this pull request Jan 7, 2020
The performance of TRUNCATE is slower than DELETE FROM.

Probably due to

Note that this provides a way to stop hacking core
civicrm/civicrm-packages#180
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants