Java: Surround injected SQL dynamically
In our project, we have methods that take a WHERE condition as string literal parameter.
Using SQL injection directly, this really work because the partial query isn't proper SQL and fails syntax checks and age and name don't resolve to proper columns.
students.where("age > 10 AND name LIKE 'Doe%'");
I would like to create a plugin/language injection extension that provides the context within which the SQL is evaluated.
I would imagine something like:
prefix = "SELECT * FROM " + determineTable() + " WHERE";
postfix = ""
Are there any hooks I can use to facilitate this functionality?
Please sign in to leave a comment.
Hi! If I understand correctly what you want then probably `MultiHostRegistrar.addPlace` `suffix` and `prefix` parameters it what you are searching for
Thanks for the quick reply, I've got some preliminary working stuff using the LivePlugin so far. I will post the code for future reference later.
Follow up question: Do I need to change something to get syntax highlighting working in the injected literal? I can do Alt-Enter -> Edit SQL and get an editor with working syntax highlighting and my custom prefix shows up and isn't editable, which is great.
Also, within the injected literal, I get proper completion, symbol navigation etc, but no highlighting.
Follow up question 2: When I'm on some string expression, a combination of concatenation with literals and variables, IntelliJ offers "Inject Language". Then, when using "Edit fragment", the string will show up with "holes" that are greyed out.
Can I also do that with the MultiHostRegistrar?
1. Highlighting should work out-of-the-box, please check logs for any errors
2. You could do it by calling `addPlace` for each concatenation operand within one `startInjecting`/`donetInjecting` wrap. Implementing `ConcatenationAwareInjector` could help with getting all operands.
1. You were right, I had an NPE in my MultiHostRegistrar
2. addPlaces called multiple times
So far, I've used it to get a getAllWhere(Entity.class, "<where>", "<order by columns"); working:
Java code:
Why isnt' the "ORDER BY" displayed in the editor? it shows in the PsiViewer. As soon as I *click* on the ", " placeholder, it gets replaced with an uneditable order by and the placeholder disappears
the current call sequence is:
addPlace("SELECT * FROM table ", null..., where, range)
addPlace(" ORDER BY ", null..., orderBy, range)
Is this intended behavior?
I haven't yet looked into COncatenationAwareInjector much. It seems as if this is itself being used within JavaConcatenationInjectorManager ?
https://upsource.jetbrains.com/idea-ce/file/idea-ce-a5f4151611972df8502464fa96cd0004881bef1d/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java?nav=3432:3496:focused&line=57&preview=false
Looks like I would also need my own copy of computeAnchorsAndOperands ?
https://upsource.jetbrains.com/idea-ce/file/idea-ce-a5f4151611972df8502464fa96cd0004881bef1d/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java?nav=7373:7397:focused&line=210&preview=false
I see ConcatenationAwareInjectors can be registered via an extension point, would I then need to determine the "context" (i.e. whether I'm in the method call I'm interested in) manually?
For future reference, here's the code that I'm using in combination with LivePlugin to facilitate the dynamic SQL injections:
> Why isnt' the "ORDER BY" displayed in the editor?
> Is this intended behavior?
Yes, it is intended behaviour, in the fragment-editor all suffixes replaced by a placeholder with text taken from original file text between injected parts. And moreover, in IDEA 2018.3 placeholders will become non-unfoldable. Please roll an issue in youtrack if you want more control over it.
> Looks like I would also need my own copy of computeAnchorsAndOperands ?
You need it if you want to keep using MultihostInjector but to get access to other operands. Otherwise If you implement ConcatenationAwareInjector instead of MultihostInjector you will get all operands instead of one and you can work with them same way you did it with one.
> I see ConcatenationAwareInjectors can be registered via an extension point, would I then need to determine the "context" (i.e. whether I'm in the method call I'm interested in) manually?
yes, you could do it by walking PSI tree
Thanks again for the reply.
I don't really mind if it's non-unfoldable. As a user, it would not make sense to me, however, that I could see the prefix but not parts in between.