-
Notifications
You must be signed in to change notification settings - Fork 834
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
fix(postgresql): set query result column nullable if selected column contains json operator or null value in case expression #3739
base: main
Are you sure you want to change the base?
Conversation
Can we add this test case as well please?
|
Where in your tests are we setting the expectation of the generated results? Or is the committed code the expectation? |
GetNullable3B added
In my PR description I proposed type precedence, for multiple type inside case expression. For example
and so on. but on the other side, I think that the user should be given freedom if the return value of case expr has several type variance (in short, just return |
I have generated the result using code from this PR, and then make it as expectation (commited on repo), but to be honest I have a problem in github workflow tests, it seems that the binary that the workflow use is the previous version before I made these changes, so the generated go file would always be different than the one I commited on the repo. Especially on |
…s printed selected columns without parentheses, it will generate different type on from query.sql
dcf4684
to
e7ddabf
Compare
So after thinking about it, I realized we really only care about what Postgres thinks the returned values are, not what we think they should be. For example, if you insert at least 4 rows into SELECT CASE
WHEN id = 1 THEN '1'
WHEN id = 2 THEN null
WHEN id = 3 THEN id
WHEN id = 4 THEN 4.5
ELSE '10'
END
FROM "mytable"; Returns:
The strings for But if you change the query to this: SELECT CASE
WHEN id = 1 THEN '1'::text
WHEN id = 2 THEN null
WHEN id = 3 THEN id
WHEN id = 4 THEN 4.5
ELSE '10'
END
FROM "mytable"; You get an error: or this: SELECT CASE
WHEN id = 1 THEN 'foobar'
WHEN id = 2 THEN null
WHEN id = 3 THEN id
WHEN id = 4 THEN 4.5
ELSE '10'
END
FROM "mytable"; You get a similar error: So to sum up: I think you are on the right track, with forcing these types of queries into a type rather than an any/interface{} I don't know how realistic these are in the real world. Perhaps we should try to find queries that hit an actual table of data, rather than case statements of literals. |
I agree that it's not quite realistic, I better left it to sqlc user to decide which data type that will be used in case of multiple data type exist on case-when-then-else. In short, I'll make it interface then |
# Conflicts: # go.sum
… user more freedom to choose query column type
col = &Column{Name: name, DataType: "float", NotNull: true} | ||
case *ast.Boolean: | ||
col = &Column{Name: name, DataType: "bool", NotNull: true} | ||
case *ast.Null: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is new addition to handle null const value. I need to distinguish between any
and null
, because null
in CaseExpr
would determine query column result nullability, but does not make it included in column type decision.
for ast.A_Const
condition, i have converted DataType null
back to any
(line 136, outputColumns
function) because we don't know its type and to preserve backward compatibility
} | ||
} else { | ||
cols = append(cols, &Column{Name: name, DataType: "any", NotNull: false}) | ||
defaultCol = &Column{Name: name, DataType: "null", NotNull: false} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing ELSE
clause on CaseExpr is considered to return null value
Based on the tests, I believe this fixes the issue for me. |
from my previous PR, I mentioned @kyleconroy to ask for review. would you mind checking it @kyleconroy? sorry i still can't assign reviewer for this PR |
Trying to solve #3710
JSON traversal operator on selected columns
Based on postgresql docs, operator
->>
and#>>
should return string, and since this is JSON and it could have null value on its field, it should returnpgtype.Text
. Other JSON operator should returninterface{}
since it returns JSON objectRefactor AExpr and AConst on selected columns
Since it is used on CaseExpr, I refactored both of them to allow it to be reusable in different location
TypeCast null value checking
If there is any selected columns which has null value to be casted to other type, for example
null::text
then it should returnpgtype.Text
to allow nullable textCaseExpr nullable + column type handling
Previously, sqlc determines column type from default case and uses hardcoded
NotNull
totrue
. Relying on default case can be bad since it might not be declared, if user decides not to useELSE
keyword.This PR will determine column type + nullability from all sub-case, on list of
THEN
clause combined withELSE
clause considering data types involved on those multiple clause.interface{}
typeinterface{}
typeELSE
resultand if any of those column are nullable, then the resulting column will be set to nullable.