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

[8.x] Add method to dump the SQL query replacing all bindings #36918

Closed
wants to merge 11 commits into from
Closed

[8.x] Add method to dump the SQL query replacing all bindings #36918

wants to merge 11 commits into from

Conversation

mateusjunges
Copy link
Contributor

@mateusjunges mateusjunges commented Apr 8, 2021

About this PR

This PR adds a new toSqlWithBindings method to the Query Builder class.

It allows developers to dump the query with all binding replaced with it actual value, for example:

Post::where('title', 'like', 'Example%');

With the actual ->toSql() method, it returns this:

"select * from `posts` where `title` like ?"

Of course you can use the ->dd() method, and it returns your bindings as an array, which is useful but it kinda take some time to figure out the place for each binding within your query if you have a query with too many bindings:

"select * from `posts` where `title` like ?"
array:1 [
  0 => "Example%"
]

Using the new proposed ->toSqlWithBindings() method, you can easily see your query with all bindings:

select * from `posts` where `title` like 'Example%'

Questions

I don't know if my tests were added to the correct class. If not, tell me what class they should be in and I make the correction.

@mateusjunges mateusjunges marked this pull request as ready for review April 8, 2021 17:18
Comment on lines 2278 to 2279
if (is_object($i)) {
$i = (string) $i;
Copy link
Contributor

Choose a reason for hiding this comment

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

This will throw a fatal if the object in question does not implement __toString(), is that desired or should it be catched and turned into a logic exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tested it with SQLite, SQL Server, MySQL and PostgreSQL, and the tests still passing (i'll add the tests as a separate commit and we can drop if later if it's unnecesssary). Can you provide an example where you think the object does not implement __toString()?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure:

User::query()->where('updated_at', '>', new DateTime('yesterday'))->get();

https://3v4l.org/Xi2hT

Fatal error: Uncaught Error: Object of class DateTime could not be converted to string

Copy link
Contributor

Choose a reason for hiding this comment

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

Just to clarify:

The query from the first snippet above works on a stock Laravel installation.

The link was to show the \DateTime class fails to be cast to a string.

@rodrigopedra
Copy link
Contributor

I would look into previous attempts to see why they got rejected

Also you need to account for:

  • booleans
    • true becomes 1 and false becomes 0
    • I think true already is converted to 1 when concatenating, but false I am pretty sure gets coerced to an empty string
  • nulls
    • gets coerced to an empty string
    • should be an unquoted NULL

Another suggestion is to look how these packages handle this:

They all have some sort of full query display.

Good luck

@mateusjunges mateusjunges marked this pull request as draft April 9, 2021 02:42
@driesvints
Copy link
Member

This PR won't be reviewed until it's out of draft.

@mateusjunges mateusjunges marked this pull request as ready for review April 11, 2021 19:31
'?',
collect($this->connection->prepareBindings($this->getBindings()))
->map(function ($i) {
return (is_string($i)) ? "'{$i}'" : $i;
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it would be safer to call some existing functionality to quote query parameters, otherwise this would not work when one of the bound strings contains a single quote.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@thiagorb I think PDO quote method solve this problem. Can you check it again?

@@ -2275,7 +2275,7 @@ public function toSqlWithBindings()
'?',
collect($this->connection->prepareBindings($this->getBindings()))
->map(function ($i) {
return (is_string($i)) ? "'{$i}'" : $i;
return (is_string($i)) ? $this->connection->getPdo()->quote($i) : $i;
Copy link
Contributor

Choose a reason for hiding this comment

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

$this->connection is type-hinted as a Illuminate\Database\ConnectionInterface, which does not have a getPdo() method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rodrigopedra Do you think something like this would be better?

$search = ["\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a"];
$replace = ["\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z"];

return "'" . str_replace($search, $replace, $value) . "'";

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@taylorotwell
Copy link
Member

Thanks for your pull request to Laravel!

Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include.

If possible, please consider releasing your code as a package so that the community can still take advantage of your contributions!

If you feel absolutely certain that this code corrects a bug in the framework, please "@" mention me in a follow-up comment with further explanation so that GitHub will send me a notification of your response.

@taylorotwell
Copy link
Member

I suggest checking out tools like Telescope and DebugBar.

@mateusjunges mateusjunges deleted the feature/add-to-sql-with-bindings-method branch April 14, 2021 05:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants