Problem/Motivation
While exploring #1425794: SQLite exception "primary key must be unique" when sequences table erroneously contains more than one row, chx and I almost "fixed" the implemenation of "greatest" in SQLite driver, because the code is misleading.
Here, instead is a patch (was #9 in the other issue, but turned out to be unrelated) that simplifies the function and adds a comment to make its desired behavior clear. This behavior is that we mimic the way that the greatest function in MySQL works. If the function is called with less then two parameters a exception is called. With two or more parameters and with one or more of those parameters being NULL will return the value NULL.
The problem is that PostgreSQL works a little bit different. And there is no way we can change this. Calling greatest with one parameter just returns the parameter. With two or more parameters will only return NULL if ALL the parameters are NULL.
Steps to reproduce
Proposed resolution
Change sqlFunctionGreatest() to not fail when an argument in NULL. And mimic MySQL as explained above.
Remaining tasks
Review
Commit
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #51 | 1814762-nr-bot.txt | 85 bytes | needs-review-queue-bot |
| #49 | 1814762-49.patch | 6.17 KB | quietone |
| #49 | interdff-47-49.txt | 502 bytes | quietone |
| #47 | 1814762-47.patch | 5.68 KB | quietone |
| #47 | 1814762-47-fail.patch | 4.25 KB | quietone |
Comments
Comment #1
lotyrin commentedHmm, patch got lost.
Comment #2
lotyrin commentedComment #3
halstead commentedTesting shows this to be functionally equivalent and it is much easier to read.
I would prefer a standard if over the ternary if to make it even more readable but either way works.
I'm marking rtbc but will happily review again if you change it.
Comment #4
catchI'd prefer the if as well - wouldn't this be enough?
<?php
if (!in_array(NULL, $args, TRUE)) {
return max($args);
}
}
Comment #5
lotyrin commentedYep. I agree. Patch is what someone in the other thread came up with, I'll reroll with an if.
Comment #6
lotyrin commentedHere's the if version.
Comment #7
lotyrin commentedComment #8
alan d. commentedDon't you mean NULL rather than $null?
Comment #9
lotyrin commentedYep...
Comment #10
donquixote commentedWhat about GREATEST() with no arguments? Should this return NULL or should it break?
Comment #11
donquixote commented#10:
So, in MySQL at least it requires two arguments.
But should we try to replicate this in PHP?
What we should not do is silently fail. Either we return NULL or we throw an exception.
EDIT:
Oracle docs suggest that only one argument is required:
http://docs.oracle.com/html/A95915_01/sqfunc.htm#i1005813
Comment #12
donquixote commentedOther question: How reliable is max() for strings or datetime?
For my taste we should postpone this question to a follow-up, where we can also add tests:
#2262425: Does PHP max() correctly replicate SQL GREATEST() for non-numeric values?
Another thing to do here and now: Add a nice docblock.
Comment #13
donquixote commentedBtw, the existing implementation is not just misleading but wrong and buggy, as it can lead to count(UNDEFINED).
Maybe previous PHP versions were silent about this, but it is definitely wrong.
I am changing this to a bug report.
(Originally i came from here: #2259947: Minor bug fixes in database system)
Comment #14
jhedstromThis patch still applies. Are there any db-driver-specific tests? Could this be tested? I don't think the testbot currently runs on sqlite, but it eventually will (hopefully) run on all supported db drivers.
Comment #16
amateescu commentedMoving to the right component.
Comment #18
daffie commentedThe patch looks good to me.
The documentation from MySQL states tht there be a minimum of two parameters for the GREATEST function. It also states that if one parameter is NULL that the function will return NULL. This patch does both.
The patch still applies, so for me it is RTBC
Comment #19
alexpottIt would be nice to have some tests for this.
Comment #20
daffie commentedWith new tests for this we have to watch out for any problems with a PostgreSQL database.
Comment #21
daffie commentedTests added.
Comment #22
daffie commentedMinor change to the added tests.
Comment #23
lotyrin commentedComment #25
daffie commentedRerolled the patch from comment #22, because ConnectionTest has been moved.
Comment #28
daffie commentedAfter some strange problems with the testbot it is now happy. So back to needs review.
Comment #30
berdirThe NULL is interesting, I actually tried a quick fix in #2810325: Undefined variable $args in sqlFunctionGreatest() and got another exception as a result of that.
This happened for me in a kernel test that saved a user, so it tried to write to the sequence table.
Comment #31
daffie commentedChanging the title at @Berdirs request.
Comment #32
berdirYes, tried with this patch applied now and this is the error that I get now:
General error: 20 datatype mismatch: UPDATE {sequences} SET value = GREATEST(value, :existing_id) + 1
So I guess it wants to do NULL + 1. Still not sure why one of the values is NULL in my case.
Comment #45
smustgrave commentedPatch or MR doesn't apply anymore
The last patch or MR doesn't apply to the target branch, please reroll the code so that it can be reviewed by the automated testbot.
Would like to know if still valid bug though after 6 years
Comment #47
quietone commentedI started triage on #1425794: SQLite exception "primary key must be unique" when sequences table erroneously contains more than one row and found my way to this issue. The problematic code is still in sqlFunctionGreatest().
I decided to update the patch and add tests.
Comment #49
quietone commentedLet's try this. Still having trouble with PHPStan locally so I can't test this.
Comment #50
smustgrave commentedIS seems to match the proposed patch
#48 has a fail patch to show the tests are covering the change
All green across the different databases.
Think this is good.
Comment #51
needs-review-queue-bot commentedThe 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 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.