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

DB::raw() in whereDate() is also applied to following where clauses #22213

Closed
dattz opened this issue Nov 26, 2017 · 12 comments
Closed

DB::raw() in whereDate() is also applied to following where clauses #22213

dattz opened this issue Nov 26, 2017 · 12 comments

Comments

@dattz
Copy link

dattz commented Nov 26, 2017

  • Laravel Version: 5.4
  • PHP Version: 7.0.8
  • Database Driver & Version: MySQL 5.7.20

Description:

If DB::raw() is used in whereDate(), the following where clauses also get the same value supplied to DB::raw().

Steps To Reproduce:

  1. Create an Eloquent which has at least two columns and one of them is a timestamp (I created a ordered_on timestamp field and status varchar field).
  2. Build a query that uses DB::raw() in whereDate() and uses another where clause followed by it (The order matters. First use the, whereDate(), then use the other where method). Example:
    Orders::whereDate('ordered_on', '>', \DB::raw('CURDATE()')->where('status', 'Complete');
  3. Notice the query executed - It should be:
    select * from 'orders' where date('ordered_on') >= CURDATE() and 'status' = 'CURDATE()'

Notice the 'status' = 'CURDATE()'.

@laurencei
Copy link
Contributor

does it occur in 5.5?

@davidcb
Copy link

davidcb commented Nov 27, 2017

I have tested it on 5.5.21 and it still occurs.

$accounts = Account::whereDate('created_at', '>', \DB::raw('CURDATE()'))->where('name', 'Complete')->get();

generates the next query string:

select * from `accounts` where date(`created_at`) > CURDATE() and `name` = 'CURDATE()'

@srmklive
Copy link
Contributor

If you do it like this:

$accounts = Account::whereDate('created_at', '>', 'CURDATE()')->where('name', 'Complete')->get();

Does it throws an error or works exactly like you expected?

@davidcb
Copy link

davidcb commented Nov 27, 2017

With that code it works:

select * from `accounts` where date(`created_at`) > 'CURDATE()' and `name` = 'Complete'

So the problem seems to be only with the method DB::raw in whereDate, as @dattz pointed.

@Miguel-Serejo
Copy link

It looks like the value is bound twice, as any subsequent where clause bindings will be shifted over, rather than replaced:

App\User::whereDate('created_at', '<', \DB::raw('CURDATE()'))->where('name', 'John Doe')->where('email', 'john@example.com')->get();

results in:

select * from `users` where date(`created_at`) < CURDATE() and `name` = 'CURDATE()' and `email` = 'John Doe';

As a workaround, consume the extra bound value in a way that won't alter your query, such as:

App\User::whereDate('created_at', '<', \DB::raw('CURDATE()'))->whereRaw('? is not null')->where('name', 'John Doe')->get();

which results in something like:

select * from `users` where date(`created_at`) < CURDATE() and 'CURDATE()' is not null and `name` = 'John Doe';

@srmklive
Copy link
Contributor

Honestly i wouldn't use DB::raw() for using native MySQL functions for a value, when i can simply use it inside a string. `You could write the code as mentioned by @dattz like this:

$accounts = Account::whereRaw('created_at > CURDATE())->where('name', 'Complete')->get();

@Miguel-Serejo
Copy link

Miguel-Serejo commented Nov 27, 2017

@srmklive Slight correction, you forgot to add the date part of the query (whereRaw('date(created_at)(...)), and that's important because what you wrote would be equivalent to using where() which does not suffer from this bug.

I guess turning the whereDate into a whereRaw is probably a more sensible workaround than consuming the extra binding.

In any case, this is still a bug in the framework that should be fixed.

@brechtdedecker
Copy link

Hmm I'm doing this query :
Order::whereDate('ordered_on', '>', \DB::raw('CURDATE()'))->where('status', 'Completed');

and my sql script looks like this : "select * from orders where date(ordered_on) > CURDATE() and status = ?"

@brechtdedecker
Copy link

I would suggest you using the Carbon library to get the current date.

@brechtdedecker
Copy link

executing :

Orders::whereDate('ordered_on', '>', \DB::raw('CURDATE()'))->where('status', 'Complete')->get();

generates the following input in the querylog:

array:1 [▼
0 => array:3 [▼
"query" => "select * from orders where date(ordered_on) > CURDATE() and status = ?"
"bindings" => array:2 [▼
0 => Expression {#113
#value: "CURDATE()"
}
1 => "Complete"
]
"time" => 2.45
]
]

Is this kinda what you we're looking for ?

@brechtdedecker
Copy link

If the bug is not already fixed, I would like to try and solve it, could anyone confirm that this issue is still open ?

@brechtdedecker
Copy link

Well using the whereDate seems to be the issue, cause when using a where clause like this:

Orders::where('ordered_on', '<', \DB::raw('CURDATE()'))->where('status', 'Complete')->get();

dd(DB::connection()->getQueryLog());

->

array:1 [▼
0 => array:3 [▼
"query" => "select * from orders where ordered_on < CURDATE() and status = ?"
"bindings" => array:1 [▼
0 => "Complete"
]
"time" => 2.11
]
]

seems to work fine.

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

No branches or pull requests

6 participants