Skip to content

Sqlite support both integer and field reference intervals in date functions#2482

Closed
vhraban wants to merge 3 commits intodoctrine:4.0.xfrom
vhraban:feature_sqlite_support_both_int_string_in_date_functions
Closed

Sqlite support both integer and field reference intervals in date functions#2482
vhraban wants to merge 3 commits intodoctrine:4.0.xfrom
vhraban:feature_sqlite_support_both_int_string_in_date_functions

Conversation

@vhraban
Copy link
Copy Markdown

@vhraban vhraban commented Aug 25, 2016

I stumbled upon a problem that my query worked in MySQL but not SQLite. As it turns out, when using SQLite it is not possible to perform date arithmetic on field references, only on actual integers.

This works

$qb = $this->repo->createQueryBuilder('foo');
$qb->join("foo.bar", "bar")
       ->where("CURRENT_TIMESTAMP() BETWEEN
                            DATE_SUB(foo.time, 1, 'hour')
                     AND
                            DATE_SUB(foo.time, 2, 'hour')
                     ");

generating (roughly)

SELECT foo.time
INNER JOIN bar ON foo.bar_id = bar.id
WHERE CURRENT_TIMESTAMP() BETWEEN
DATETIME(foo.time,"-1 HOUR")
AND
DATETIME(p0_.time,"-2 HOUR");

This does not

$qb = $this->repo->createQueryBuilder('foo');
$qb->join("foo.bar", "bar")
       ->where("CURRENT_TIMESTAMP() BETWEEN
                            DATE_SUB(foo.time, bar.start, 'hour')
                     AND
                            DATE_SUB(foo.time, bar.end, 'hour')
                     ");

Because this will get generated

SELECT foo.time
INNER JOIN bar ON foo.bar_id = bar.id
WHERE CURRENT_TIMESTAMP() BETWEEN
DATETIME(foo.time,"-bar.start HOUR")
AND
DATETIME(p0_.time,"-bar.end HOUR");

My fix adds support to reference other fields in the query, so that the first code example works the same way, but the second one uses SQLite concat symbol and generates the following:

SELECT foo.time
INNER JOIN bar ON foo.bar_id = bar.id
WHERE CURRENT_TIMESTAMP() BETWEEN
DATETIME(foo.time,"-" || bar.start || " HOUR")
AND
DATETIME(p0_.time,"-" || bar.end || " HOUR");

I've got only two concerns regarding this:

  • Currently functional tests do not check for this case at all, but I added an SQLite platform test. Is this enough?
  • I had to modify PHPDocs in AbstractPlatform to reflect that some methods now accept string or integer as $interval for date arithmetics. I know for sure this is the case for MySQL and, given this fix, SQLite, but other platforms may not support it. This brings inconsistency in what different platforms support

* @param string $date
* @param integer $seconds
* @param string $date
* @param integer|string $seconds
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

All of these should be reverted: we shouldn't accept strings, and should be very strict about this due to SQL injection concerns

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see what you mean by this, but string is not valid here. Must be something like an expression object, or a field reference. /cc @deeky666

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

As far as I know, there is no Expr to represent datetime arithmetics. Field reference can not be represented as a data type either. Leaving this just an integer does not reflect how this method can be used. I can not see any good way of doing this PHPDoc at all apart of introducing datetime Expr that goes far beyond this issue. What would you suggest?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No, what I'm saying is creating an Expr object or such. Passing around strings here is just going to be causing more and more problems in the future :(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@deeky666 do you have suggestions about how to design this API, eventually?

@vhraban vhraban changed the title Sqlite support both integer and string intervals in date functions Sqlite support both integer and field reference intervals in date functions Aug 31, 2016
@vhraban
Copy link
Copy Markdown
Author

vhraban commented Sep 7, 2016

Please do not close this ticket due to inactivity, I will have a proper look into it the next week

Base automatically changed from master to 4.0.x January 22, 2021 07:43
@morozov morozov closed this Oct 26, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants