Spin off from #3399150: [PP-1] Enable dynamic queries to produce SQL with positional placeholders.

Problem/Motivation

While working on #3399150: [PP-1] Enable dynamic queries to produce SQL with positional placeholders, I got fed up by the low readability of the SQL strings dumped when exceptions occur, both in PHPUnit (or other CLI) output and in site pages.

So I spent some time trying to improve them.

Before CLI
before html

After CLI
before html

Before HTML
before html

After HTML
before html

Proposed resolution

  • Introduce a dev dependency for doctrine/sql-formatter, which has a good tokenizer and CLI / HTML dumpers.
  • Use doctrine/sql-formatter for dumping SQL strings and symfony/var-dumper for dumping the placeholders values.
  • Create an utility helper class to allow formatting, self-detecting whether CLI or HTML output should be produced.
  • Use the class for formatting output produced by database ExceptionHandler implementations.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork drupal-3609986

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mondrake created an issue. See original summary.

mondrake’s picture

Issue summary: View changes
StatusFileSize
new586.31 KB
new722.37 KB
new159.44 KB
new308.1 KB
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes

mondrake’s picture

Status: Active » Needs review
longwave’s picture

Can the SQL formatter actually do the placeholder replacement as well? Sometimes I want to copy and paste the statement and run it manually - and that is always painful (the quoted field names don't help here either, but that's a separate problem)

Having said that it might be better to show the placeholders separately for some cases, so not sure we always want this.

longwave’s picture

This will need to be a runtime dependency if we are formatting runtime exception messages with it.

mondrake’s picture

There’s this https://github.com/doctrine/sql-formatter#compress-query but we’d have to do the placeholder replacements ourselves, which is tricky as it requires escaping that is Connection dependent. The library itself is db agnostic. Maybe we could do that for tests putting up a static flag to say whether a full replaced SQL string should be produced on top. My use case was different from yours, I am mainly checking for named placeholders in strings that should only have positional ones (see parent).

The MR has protection to do this only in dev (symfony/var-dumper is a dev dep, so by extension I thought to limit to dev also the sql formatting).

mondrake’s picture

the quoted field names don't help here either

Why so? Theoretically quoting column names and other db objects should be the most accurate, no?

longwave’s picture

When I copy and paste the quoted names into an SQL client then the statement won't execute until I manually remove the quotes.

mondrake’s picture

#11: weird.

Anyway if we get in the business of replacing the placeholders with their concrete escaped values, I think we can also get in the one of removing the quotes from the identifiers.

TBH I think #7 to #11 would be better dealt with in a follow-up: it’s additional req vs the need of showing the statement exactly as is executed by Drupal.

mondrake’s picture

btw #3571186: mysqli - skip prepared statement to allow async query execution is exactly doing the replacement of placeholders with their values - but that’s done at execution time and is mysqli only

mondrake’s picture

I was really puzzled by #11 so I investigated a bit.

Used a MariaDb client.

The problem is that Drupal produces ANSI standard SQL that uses double quotes to escape identifiers; at least MariaDb SQL client uses backticks by default instead. If you change " with the backtick character, the syntax passes. Alternatively, you can execute
SET sql_mode = 'ANSI,TRADITIONAL';
in the CLI before executing a Drupal statement string (which is what Drupal does in the Connection constructor, and that explains why Drupal is not failing) and double quotes will then be recognized as valid quotes for database identifiers.

mondrake’s picture

Status: Needs review » Needs work

Mmm this now will call expensive dumping for every database exception, but many are caught before producing any output. Let’s try to restrict dumping to only when it’s needed.

mondrake’s picture

Status: Needs work » Needs review

Done #15

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new91 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

mondrake’s picture

Status: Needs work » Needs review
needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new91 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

mondrake’s picture

Status: Needs work » Needs review
needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new98 bytes

The Needs Review Queue Bot tested this issue. The merge request has merge conflicts and cannot be merged. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

mondrake’s picture

Status: Needs work » Needs review
mondrake’s picture

Status: Needs review » Needs work

We may just pass the value object in SqlDumper::export() instead of the 3 args.