Plugin to evaluate custom schema tokens in injected SQL

Answered

Let's consider I have a project where I define sql queries in xml (spring) files:

 

<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
    <bean id="query1" class="com.example.demo.db.Query">
        <property name="selectSql">
            <value><![CDATA[
                select ID, NAME   
                from :schema.USERS  
                where ID = :idParam
                ]]></value>
        </property>
    </bean>
</beans>

The injected query above fails to validate in IntelliJ due to the “:schema” parameter. :schema is not a proper parametrized value (since parameters can't be used for schemas or table names). While our application code replaces the :schema parameter to a literal value, so the queries execute correctly, I'd like intellij to correctly parse these queries as well, so I can get query validation and autocomplete. I explored some approaches to write a plugin that would internally replace :schema value in the PSI structure to the actual value (which can be the currently selected schema in the database toolbar), so the xml file is not altered, but the sql parser or validator can see the correct value. I've not been successful in this approach, due to lack of experience with PSI internals and framework. What would be the best approach/extension point to handle this scenario? Appreciate if you could point me in the right direction.

0
3 comments

Please try using com.intellij.lang.injection.MultiHostInjector or  com.intellij.languageInjectionPerformer extension point https://plugins.jetbrains.com/docs/intellij/language-injection.html 

0

Thanks Yann, I'm able to inject SQL languages in xml through MultiHostInjector, or directly via IDE settings, that's not a problem. My challenge is, how do I replace the :schema token by the currently selected schema on the currently opened file, without altering the file contents?  Do I need to create a new SQL dialect? Do I need to overwrite the sql lexer? Do I use Reference Providers? (this was suggested by Claude/Chatgpt, but I've not been able to make that work). The :schema text should not change in the file, but the correct schema value, taken from the currently selected schema in the db toolbar, should be used for validations, autocomplete, etc.

The second, less important challenge, is how do I get the currently selected schema from the db toolbar :)

Thanks

0

Does this resolve your issue?

Regarding accessing database API, see https://youtrack.jetbrains.com/issue/IJSDK-104 

      val text = ElementManipulators.getValueText(host)
      val i = text.indexOf(":schema")

      val valueTextRange = ElementManipulators.getValueTextRange(context)
      registrar.startInjecting(SqlLanguage.INSTANCE)

      val beforeSchema = TextRange.from(valueTextRange.startOffset, i)
      registrar.addPlace(null, null, host, beforeSchema)
      val afterSchema = TextRange.create(beforeSchema.endOffset + ":schema".length, valueTextRange.endOffset)
      registrar.addPlace(
        "postgres.public" /* something should be placed instead of :schema in SQL*/,
        null,
        host,
        afterSchema
      )

      registrar.doneInjecting()
0

Please sign in to leave a comment.