-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
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
SQL Syntax error when empty array is given into "In" method #2195
Comments
Uhh hard to decide which one should be applied. I need more opinions on this topic. |
I'd prefer parameters to be validated but I think it's also ok as it is as long as there is a clearer exception message and explicit documentation explaining that parameters should be validated before passing them to typeorm. |
I don't think it will be possible to catch this at the Typescript layer - Typescript doesn't differentiate between empty arrays vs. arrays with entries, so we can't type-check this. I do think that have some kind of runtime check would be valuable. Something that throws if you supply an empty array to
Strongly disagree. This is a semantically different query. I.e. it's possible
Same here. This fundamentally changes the query, leading to potentially dangerous results. What happens if I do an |
@davewasmer @tafkanator @pleerock I believe a semantically equivalent clause that could replace the |
@benmesirow I agree that if we had to translate However - I don't think the goal here should be "TypeORM will take your invalid SQL syntax and try it's best to transform it into something that is valid". If the user is calling So why might someone do |
I don't think we should throw an error here - maybe in most cases users would assume passed array isn't empty, but we can't guarantee if someone is aware that array might be null. In that case executing query with success but without results is expected. But if we know that query will have no results do we really have to execute it? Or maybe just execute it with |
But if that's the case, they are essentially telling TypeORM to build invalid syntax. There are other ways to get TypeORM to build a query that returns no results.
If you want a query with no results, you can add your own I go back to my last point above. Perhaps someone might want the "return empty set rather than error" behavior, but those folks will be a vanishingly small group, they will be aware of their hack (they won't accidentally encounter that behavior), and can achieve it other ways. Meanwhile, the vast majority of people who encounter this behavior will be people like me: they passed an array expecting it to always have values, and it didn't. Having TypeORM silently change the semantics of my query just to avoid an error could lead to maddeningly difficult-to-diagnose bugs. |
After thinking about this more I have to agree with @davewasmer; for better or for worse, SQL doesn't support filtering by membership in an empty set, and there's no reason why an empty check on an array can't be preformed prior to composing the typeorm query, which will result in a more efficient query for cases where the array is in fact empty. |
Depends on how you look at it.
I could say something similar - you can always check length of the array before running the query. Or we could just see how other ORM deals with such situations. |
If TypeORM's API was a higher level abstraction over SQL, then I would agree. But the QueryBuilder API is pretty close to a 1:1 mapping over SQL concepts. In other words - I think transforming to a filter would be fine if the method was called I think I've made my case at this point, and it doesn't seem like there's a lot of new information coming from further discussion. I'm happy to elaborate further if any of my points are unclear, but I also don't want to belabor the point if you're not interested in changing this behavior. Thanks for your work on TypeORM @Kononnable - it's great project (regardless of how this issue shakes out 😉) |
A naive but useful userland solution, is using @davewasmer
I just wish we had this sort of sanity checks inside the lib, since it lib can tell at runtime that translating an empty array And this doesn't break the query at all, it's semantically equivalent and would return the same result of the query if |
On that note, here's a functional solution for private createTypeConditions = async (type: string) => {
const ids = await this.getIdsForType(type);
return {
id: ids.length > 0 ? In(ids) : Raw(() => 'FALSE'),
};
}; |
There is workaround. You can do:
|
IMO the way typeorm treats find({where: {key: [null, 1, 2]}) // => where key is null or key in (1,2)
find({where: {key: [undefined]}) // => where key is null
find({where: {key: []) // => where 1 = 0 |
@bogdan I disagree. |
@1valdis SQL is 30 years old. There are many brave enough to fix its design issues in other ORMs that are already doing that. TypeORM is behind by not doing that and denying progress. |
It's Working, Thanx @Ginden |
I'll have to agree with people saying it's better to throw an error. I've encountered this problem some days ago and, while I was able to see what's wrong, it would have been much faster if Typeorm had told me about the issue. However, it may be best to just return a warning instead of an error, if that's possible. By doing this, it would help people who encountered the problem accidentally (which I believe is most people) and wouldn't impede people who were doing it on purpose. Just adapting it to some other query would probably be disastrous, though |
I've been spending time looking through how other similar frameworks handle it: I was back and forth thinking about this and the best way to approach the problem - to throw an error or to keep on trucking on. In a lot of ways it's nice to throw an error because it'd be explicit - but I think it's also good to think through the intent of the empty array - If you say "I want anything that matches the things in here" and there's nothing there - then there can be no matches. Also, I can't find anything that actually throws an error - and I am always iffy on building an API that goes against the grain. I'll be opening a PR shortly to work on this. |
I really didn't expect this result in the search of how other frameworks handle this, interesting. And yeah, I get that it might be weird to do something so different than others have been doing. I also have to admit that I don't have much experience, so my POV may be a bit skewed because of that. However, I still think that a warning really would be the best of both worlds, as it neither breaks any code nor keeps developers in the dark. Anyway, cool to learn that it will be handled one way or another. I'm looking forward to seeing how it will work |
Also - for some dialects we are already handling an empty array: typeorm/src/query-builder/QueryBuilder.ts Lines 919 to 922 in 0280cdc
But not all of them. |
Also, I just realized that this comment section is talking specifically about mysql and mariadb so I think it's nice to add that it happens in mssql too, which is where I experienced it. Sorry if this makes my comments irrelevant or if I should be commenting on another issue/creating my own for this. But it's the same issue, anyway |
I was actually doing the research separately for opening a PR and then found this issue as well :) There's a lotta issues so I sometimes miss some.
This issue is across all dialects, so don't worry about that. I have a branch where I'll be getting this change in & opening a PR - it's currently only got the change to our tests to verify the behavior is currently not working & the tests for that are running here |
Cool, I'll definitely check those links out when I get to my computer tomorrow. Thanks for letting us know how things are going.
Of course, it's probably almost impossible to keep track of everything. I sometimes can't even keep track of my own small repos hahaha |
we were supporting an empty `IN` clause for MySQL and Oracle and this updates the handling to be for all other dialects as well by making the "empty" clause be `0=1` fixes typeorm#2195
we were supporting an empty `IN` clause for MySQL and Oracle and this updates the handling to be for all other dialects as well by making the "empty" clause be `0=1` Closes typeorm#4865 fixes typeorm#2195
This Issue is closed, but there is still a similar problem with the query builder. Foos.createQueryBuilder('foo')
.where(`foo.bar NOT IN (:...xs)`, { xs: [] }) // QueryFailedError |
@syuilo Use:
|
Thats true. Quick workaround is to pass new array like |
Issue type:
bug report
Database system/driver:
mysql
/mariadb
TypeORM version:
0.2.5
example code:
Generated SQL is similar to
In MySql
IN ()
(empty IN) is a syntax error. To fix it i propose that either:In
method with guard for checking array.length to be > 0 (this would be closest to mysql spec)In
method converts empty array toFALSE
so the result would be similar toIN()
clause (may or may not create other sql syntax errors)The text was updated successfully, but these errors were encountered: