2

I am trying to execute a query like the following, using HQL, that uses a native SQL function (dbms_lob.getlength):

def results = Attachment.executeQuery(
    'select id, originalFilename, dbms_lob.getlength(a.fileBytes), dateCreated, createUserName '+
    'from Attachment a where a.id not in '+
         '(select attachmentId from SpecVersion sv where sv.attachmentId is not null) '+
    'and a.dateCreated > sysdate - 30')
  • The fileBytes column is a BLOB - I am trying to get the size of the BLOB content.

However, this results in the error below.

java.lang.IllegalStateException: No data type for node: org.hibernate.hql.ast.tree.MethodNode
 +-[METHOD_CALL] MethodNode: '('
 |  +-[METHOD_NAME] IdentNode: 'dbms_lob.getlength' {originalText=dbms_lob.getlength}
 |  \-[EXPR_LIST] SqlNode: 'exprList'
 |     \-[DOT] DotNode: 'attachment0_.file_bytes' {propertyName=fileBytes,dereferenceType=ALL,propertyPath=fileBytes,path=a.fileBytes,tableAlias=attachment0_,className=com.et.layoutmgr.grails.mapping.Attachment,classAlias=a}
 |        +-[ALIAS_REF] IdentNode: 'attachment0_.ATTACHMENT_ID' {alias=a, className=com.et.layoutmgr.grails.mapping.Attachment, tableAlias=attachment0_}
 |        \-[IDENT] IdentNode: 'fileBytes' {originalText=fileBytes}

        at org.hibernate.hql.ast.tree.SelectClause.initializeExplicitSelectClause(SelectClause.java:156)
        at org.hibernate.hql.ast.HqlSqlWalker.useSelectClause(HqlSqlWalker.java:857)
        at org.hibernate.hql.ast.HqlSqlWalker.processQuery(HqlSqlWalker.java:645)
        at org.hibernate.hql.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:685)
        at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:301)
        at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:244)
        at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:256)
        at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:187)
        at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:138)
        at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101)
        at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
        at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:124)
        at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:156)
        at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:135)
        at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1770)
        at org.codehaus.groovy.grails.orm.hibernate.metaclass.ExecuteQueryPersistentMethod$2.doInHibernate(ExecuteQueryPersistentMethod.java:81)
        at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
        at org.springframework.orm.hibernate3.HibernateTemplate.executeFind(HibernateTemplate.java:343)
        at org.codehaus.groovy.grails.orm.hibernate.metaclass.ExecuteQueryPersistentMethod.doInvokeInternal(ExecuteQueryPersistentMethod.java:79)
        at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractStaticPersistentMethod.invoke(AbstractStaticPersistentMethod.java:72)
        at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractStaticPersistentMethod.invoke(AbstractStaticPersistentMethod.java:65)

Is something like this possible using HQL, or do I need to switch to using native SQL?

4
  • 3
    I think you will need native SQL. Commented Mar 11, 2016 at 1:27
  • 3
    Also you can try calculating this value using Formula: stackoverflow.com/a/2986354/1799527 Commented Mar 11, 2016 at 2:04
  • If your application use only Oracle, you can use native SQL or a formula in your mapped bean (written in SQL). If your application works on multi dialect, so you must write queries in native SQL called in order of your dialect Commented Mar 11, 2016 at 11:27
  • @SandeepPoonia could you add that as an answer? Seems more straightforward than using a custom dialect. Commented Mar 11, 2016 at 16:54

3 Answers 3

3

In Attachment domain add new field Long fileBytesLength and inside mapping closure add the formula for calculating the length of fileBytes field.

class Attachment {

    String createUserName
    String originalFilename

    byte[] fileBytes
    Long fileBytesLength

    Date dateCreated
    //Other Properties

    static mapping = {
        //Other mappings
        fileLength formula: "dbms_lob.getlength(fileBytes)"
    }
}

And then modify the query to:

def results = Attachment.executeQuery(
    'select id, originalFilename, fileBytesLength, dateCreated, createUserName '+
    'from Attachment a where a.id not in '+
         '(select attachmentId from SpecVersion sv where sv.attachmentId is not null) '+
    'and a.dateCreated > sysdate - 30')
Sign up to request clarification or add additional context in comments.

Comments

3

Well i achieved this by adding custom functions like this in an Overwritten dialect.

class MySqlDialect extends MySQL5InnoDBDialect {

    public MySqlDialect() {
        super();
        registerFunction("date_add_interval", new SQLFunctionTemplate(StandardBasicTypes.DATE, "date_add(?1, INTERVAL ?2 ?3)"));
        registerFunction("date_sub_interval", new SQLFunctionTemplate(StandardBasicTypes.DATE, "date_sub(?1, INTERVAL ?2 ?3)"));
        registerFunction("to_date", new SQLFunctionTemplate(StandardBasicTypes.DATE, "str_to_date(?1, ?2)"));
        registerFunction("minutes_diff", new SQLFunctionTemplate(StandardBasicTypes.LONG, "timestampdiff(MINUTE, ?1, ?2)"));
    }

    public String openBlobSelectQuote() {
        return "`";
    }

    public String closeBlobSelectQuote() {
        return "`";
    }
}

Update : Function Registration:

    registerFunction("getlength", new SQLFunctionTemplate(StandardBasicTypes.LONG, "dbms_lob.getlength(?1)"));

Your HQL Query:

def results = Attachment.executeQuery(
    'select id, originalFilename, getlength(a.fileBytes), dateCreated, createUserName '+
    'from Attachment a where a.id not in '+
         '(select attachmentId from SpecVersion sv where sv.attachmentId is not null) '+
    'and a.dateCreated > sysdate - 30')

2 Comments

Could you add an example of what the HQL and registerFunction would look like for using dbms_lob.getlength? See this example
Updated my Answer.
0

You can always use basic java jdbc connection in order to execute query. Create the java code for this and store it in src/java/.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.