Problem/Motivation
As a developer using PostgreSQL DBMS, I'm able to use LEAST() SQL function to return the lowest value from a list of given values.
But, I'm using SQLite during KernelTests for performance reasons, and this LEAST() function is not recognized, therefore my original SQL query is not a valid statement.
Proposed resolution
We can make this function available by creating a SQLite function thanks to $pdo->sqliteCreateFunction().
Since a similar task has already been done for GREATEST(),
I'm wondering if we can inspire from $pdo->sqliteCreateFunction('greatest', [__CLASS__, 'sqlFunctionGreatest']);
So, my proposal is
in `/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php`,
- to write a static method called `sqlFunctionLeast` that covers `least` keyword.
- to apply it on sqlite thanks to $pdo in the `Connection::open()` method. (like this: `$pdo->sqliteCreateFunction('least', [__CLASS__, 'sqlFunctionLeast']);`)
Technical concerns
`LEAST()` function behaves in a sightly different way depending on the DBMS.
Examples
- With PostgreSQL, `LEAST()` will return NULL as the lowest value, only if all the given values are NULL, regarding this documentation
- With MySQL, `LEAST()` will return NULL as the lowest value, if any of the given values is NULL, regarding this documentation
For my use-case, I used the PostgreSQL definition of `LEAST()`. Accordingly, these scenarios should be covered:
$values = ['A', 'B', 'C', NULL];
sqlFunctionLeast($values); // must return A;
$values = [1, 2, 3, -1, NULL, FALSE, 0];
sqlFunctionLeast($values); // must return -1;
$values = [1, 2, 3, NULL];
sqlFunctionLeast($values); // must return 1;
$values = [NULL, NULL];
sqlFunctionLeast($values); // must return NULL;
I attached a PATCH for drupal 8.7.x version, so anyone else that needs this can use it and I will port it on 8.8.x ASAP.
And we can discussed the implementation below.
Comment | File | Size | Author |
---|---|---|---|
#27 | 3120892-27.patch | 2.3 KB | ravi.shankar |
#27 | interdiff_25-27.txt | 978 bytes | ravi.shankar |
Comments
Comment #2
daffie CreditAttribution: daffie commentedHi @julienjoye: Thank you for your patch!
The patch looks good. To get this patch committed there needs to be automated testing. We want to be sure that the new code does what it suppost to do and we want to make sure that somebody later does not accidently removes the added code. My suggestion would be to add what we call a KernelTest. See:https://www.drupal.org/docs/8/testing/types-of-tests-in-drupal-8. Add a new test class called SelectLeastTest in the directory "core/tests/Drupal/KernelTests/Core/Database/". In that class add a test with a provider method. See: https://phpunit.readthedocs.io/en/9.0/writing-tests-for-phpunit.html#dat... and search our code for the key "dataProvider". I will help you and review your patch.
Comment #3
kkalashnikov CreditAttribution: kkalashnikov at Srijan | A Material+ Company for Drupal India Association commentedComment #4
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #5
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedPreapred test case only.
Comment #6
daffie CreditAttribution: daffie commented@Kumar Kundan: Thank you for working on this issue.
The test in not testing the SQL LEAST operator. Can we change the test to:
To make this test work the test need to be a Kernel test.
I changed the row of arguments into an array. In this way we can test more combinations.
Comment #7
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedThanks @daffie. I started working on this approach.
Comment #8
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #9
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #10
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedI am working for Patch Improvment of SQLite database.
Comment #11
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #12
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #13
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #14
daffie CreditAttribution: daffie commentedPatch looks a lot better.
Could we add a comment to this line. Something like: "Remove all NULL, FALSE and empty strings values but leaves 0 (zero) values."
These line a double. This is not necessary.
Could we change the word "THE" to lowercase.
This line fails for PostgreSQL, because it interpreted the values as strings and not as intergers. I think it is best just to remove lines with negative numbers.
Comment #15
ravi.shankar CreditAttribution: ravi.shankar at OpenSense Labs commentedHere I have tried to address comment #14, please review.
Comment #17
daffie CreditAttribution: daffie commentedThese are double. We do not need to test the same thing twice.
Comment #18
ravi.shankar CreditAttribution: ravi.shankar at OpenSense Labs commentedHere I have addressed comment #17
Comment #20
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #21
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #22
ravi.shankar CreditAttribution: ravi.shankar at OpenSense Labs commentedChanging status to needs review as patch #18 passed the tests.
Comment #23
daffie CreditAttribution: daffie commentedPatch looks good. Almost RTBC.
Can we remove the number zero fro the values array. The function LEAST is made for comparing items of the SAME kind.
Comment #24
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #25
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #26
daffie CreditAttribution: daffie commented#23.2 still needs to be addressed.
Comment #27
ravi.shankar CreditAttribution: ravi.shankar at OpenSense Labs commentedHere I have addressed #23.2.
Comment #28
Kumar Kundan CreditAttribution: Kumar Kundan as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedComment #29
daffie CreditAttribution: daffie commentedAll code changes look good to me.
There is testing added for the added functionality.
For me it is RTBC.
Comment #30
jungleOne question, instead of using raw SQL query, is it possible using $this->connection->select() here?
Comment #31
daffie CreditAttribution: daffie commentedThat is something that can be done. In combination with
->addExpression('LEAST(1,2,3,4,5)', 'num')
. Only I do not see how that will improve the testing coverage.Comment #32
jungle@daffie, thanks, just asking.
Comment #34
catchCommitted b5343b9 and pushed to 9.1.x. Thanks!
Comment #36
BeakerboySQL Server does not support the LEAST operator, so there are now many core testing failures under sqlsrv.