Search in sources :

Example 1 with JpqlFunction

use of com.blazebit.persistence.spi.JpqlFunction in project blaze-persistence by Blazebit.

the class SelectManager method addJpqlFunctionProcessor.

private void addJpqlFunctionProcessor(Expression expr, int index) {
    if (expr instanceof FunctionExpression) {
        String functionName = ((FunctionExpression) expr).getFunctionName().toLowerCase();
        JpqlFunction jpqlFunction = mainQuery.cbf.getRegisteredFunctions().get(functionName);
        if (jpqlFunction instanceof JpqlFunctionProcessor<?>) {
            jpqlFunctionProcessors.put(index, (JpqlFunctionProcessor<?>) jpqlFunction);
            if ("to_multiset".equals(functionName)) {
                Subquery subquery = ((SubqueryExpression) ((FunctionExpression) expr).getExpressions().get(0)).getSubquery();
                if (subquery instanceof SubqueryInternalBuilder<?>) {
                    SubqueryInternalBuilder<?> subqueryInternalBuilder = (SubqueryInternalBuilder<?>) subquery;
                    jpqlFunctionProcessors.put(index, new NestedToMultisetJpqlFunctionProcessor((JpqlFunctionProcessor<?>) jpqlFunction, subqueryInternalBuilder.getJpqlFunctionProcessors(), subqueryInternalBuilder.getSelectExpressions()));
                }
            }
        }
    } else if (expr instanceof SubqueryExpression) {
        Subquery subquery = ((SubqueryExpression) expr).getSubquery();
        if (subquery instanceof SubqueryInternalBuilder<?>) {
            SubqueryInternalBuilder<?> subqueryInternalBuilder = (SubqueryInternalBuilder<?>) subquery;
            if (!subqueryInternalBuilder.getJpqlFunctionProcessors().isEmpty()) {
                jpqlFunctionProcessors.put(index, subqueryInternalBuilder.getJpqlFunctionProcessors().get(0));
            }
        }
    }
}
Also used : JpqlFunction(com.blazebit.persistence.spi.JpqlFunction) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) Subquery(com.blazebit.persistence.parser.expression.Subquery) JpqlFunctionProcessor(com.blazebit.persistence.spi.JpqlFunctionProcessor) SubqueryExpression(com.blazebit.persistence.parser.expression.SubqueryExpression)

Example 2 with JpqlFunction

use of com.blazebit.persistence.spi.JpqlFunction in project blaze-persistence by Blazebit.

the class DataNucleusEntityManagerFactoryIntegrator method getRegisteredFunctions.

@Override
public Map<String, JpqlFunction> getRegisteredFunctions(EntityManagerFactory entityManagerFactory) {
    NucleusContext context = entityManagerFactory.unwrap(NucleusContext.class);
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) entityManagerFactory.unwrap(StoreManager.class);
    String storeName = storeMgr.getDatastoreAdapter().getVendorID();
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    Set<Object> methodKeys = fieldGet("methodNamesSupported", exprFactory, VERSION);
    if (methodKeys.isEmpty()) {
        return new HashMap<>();
    }
    Map<String, JpqlFunction> functions = new HashMap<>();
    // We need to construct a statement object and how this is done changed between 4 and 5 so we have to do a little reflection hack
    // We need this because the function methods retrieve the expression factory through it
    Class<?>[] parameterTypes = { RDBMSStoreManager.class, Table.class, DatastoreIdentifier.class, String.class };
    SQLStatement stmt;
    try {
        Constructor c = Class.forName("org.datanucleus.store.rdbms.sql.SelectStatement").getConstructor(parameterTypes);
        stmt = (SQLStatement) c.newInstance(storeMgr, null, null, null);
    } catch (Exception e) {
        try {
            Constructor c = Class.forName("org.datanucleus.store.rdbms.sql.SQLStatement").getConstructor(parameterTypes);
            stmt = (SQLStatement) c.newInstance(storeMgr, null, null, null);
        } catch (Exception e2) {
            throw new RuntimeException("Could not access the required methods to dynamically retrieve registered functions. Please report this version of datanucleus(" + VERSION + ") so we can provide support for it!", e2);
        }
    }
    // Well apparently expressions get their class loader resolver by asking the statement they are part of
    // which in turn asks the query generator that is responsible for it
    // So this is the most non-hackish way to get this to work...
    QueryGenerator noopGenerator = (QueryGenerator) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { QueryGenerator.class }, new QueryGeneratorInvocationHandler(context));
    stmt.setQueryGenerator(noopGenerator);
    for (Object methodKey : methodKeys) {
        String className = fieldGet("clsName", methodKey, VERSION);
        String datastoreName = fieldGet("datastoreName", methodKey, VERSION);
        String name = fieldGet("methodName", methodKey, VERSION);
        if (className.isEmpty() && name.indexOf('.') == -1 && ("ALL".equals(datastoreName) || storeName.equals(datastoreName))) {
            // Only consider normal functions
            SQLMethod method = exprFactory.getMethod(null, name, Collections.emptyList());
            if (method instanceof DataNucleusJpqlFunctionAdapter) {
                functions.put(name, ((DataNucleusJpqlFunctionAdapter) method).unwrap());
            } else {
                functions.put(name, new JpqlFunctionSQLMethod(stmt, method));
            }
        }
    }
    // The length function is the single exception to all functions that is based on a class
    SQLMethod method = exprFactory.getMethod("java.lang.String", "length", Collections.emptyList());
    functions.put("length", new JpqlFunctionInstanceSQLMethod(stmt, method));
    return functions;
}
Also used : JpqlFunction(com.blazebit.persistence.spi.JpqlFunction) SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) HashMap(java.util.HashMap) Constructor(java.lang.reflect.Constructor) NucleusContext(org.datanucleus.NucleusContext) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) IOException(java.io.IOException) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StoreManager(org.datanucleus.store.StoreManager) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) QueryGenerator(org.datanucleus.store.rdbms.query.QueryGenerator) SQLMethod(org.datanucleus.store.rdbms.sql.method.SQLMethod)

Example 3 with JpqlFunction

use of com.blazebit.persistence.spi.JpqlFunction in project blaze-persistence by Blazebit.

the class AbstractHibernateEntityManagerFactoryIntegrator method registerFunctions.

@Override
public EntityManagerFactory registerFunctions(EntityManagerFactory entityManagerFactory, Map<String, JpqlFunctionGroup> dbmsFunctions) {
    EntityManager em = null;
    try {
        em = entityManagerFactory.createEntityManager();
        Session s = em.unwrap(Session.class);
        Map<String, SQLFunction> originalFunctions = getFunctions(s);
        Map<String, SQLFunction> functions = new TreeMap<String, SQLFunction>(String.CASE_INSENSITIVE_ORDER);
        functions.putAll(originalFunctions);
        Dialect dialect = getDialect(s);
        String dbms = getDbmsName(entityManagerFactory, em, dialect);
        for (Map.Entry<String, JpqlFunctionGroup> functionEntry : dbmsFunctions.entrySet()) {
            String functionName = functionEntry.getKey();
            JpqlFunctionGroup dbmsFunctionMap = functionEntry.getValue();
            JpqlFunction function = dbmsFunctionMap.get(dbms);
            if (function == null && !dbmsFunctionMap.contains(dbms)) {
                function = dbmsFunctionMap.get(null);
            }
            if (function == null) {
                if (functions.containsKey(functionName)) {
                    LOG.finest("Using ORM registered function '" + functionName + "' because there is neither an implementation for the dbms '" + dbms + "' nor a default implementation.");
                } else {
                    LOG.warning("Could not register the function '" + functionName + "' because there is neither an implementation for the dbms '" + dbms + "' nor a default implementation!");
                }
            } else {
                functions.put(functionName, new HibernateJpqlFunctionAdapter(function));
            }
        }
        replaceFunctions(s, functions);
        return entityManagerFactory;
    } finally {
        if (em != null) {
            em.close();
        }
    }
}
Also used : EntityManager(javax.persistence.EntityManager) JpqlFunction(com.blazebit.persistence.spi.JpqlFunction) Dialect(org.hibernate.dialect.Dialect) SQLFunction(org.hibernate.dialect.function.SQLFunction) TreeMap(java.util.TreeMap) JpqlFunctionGroup(com.blazebit.persistence.spi.JpqlFunctionGroup) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) Map(java.util.Map) Session(org.hibernate.Session)

Example 4 with JpqlFunction

use of com.blazebit.persistence.spi.JpqlFunction in project blaze-persistence by Blazebit.

the class ScalarTargetResolvingExpressionVisitor method visit.

@Override
public void visit(FunctionExpression expression) {
    String name = expression.getFunctionName().toLowerCase();
    switch(name) {
        case "function":
            String functionName = ((StringLiteral) expression.getExpressions().get(0)).getValue();
            JpqlFunction jpqlFunction = functions.get(functionName.toLowerCase());
            if (jpqlFunction == null) {
                // Can't reliably resolve the type
                currentPosition.setAttribute(null);
                currentPosition.setCurrentType(null);
            } else {
                // Skip the function name
                resolveFirst(expression.getExpressions().subList(1, expression.getExpressions().size()), true);
                resolveToFunctionReturnType(functionName);
            }
            break;
        case "size":
            // According to our grammar, we can only get a path here
            currentPosition.setAttribute(null);
            currentPosition.setCurrentType(metamodel.type(Long.class));
            break;
        case "coalesce":
            resolveAny(expression.getExpressions(), true);
            resolveToFunctionReturnType(name);
            break;
        default:
            resolveFirst(expression.getExpressions(), true);
            resolveToFunctionReturnType(name);
            break;
    }
}
Also used : JpqlFunction(com.blazebit.persistence.spi.JpqlFunction) StringLiteral(com.blazebit.persistence.parser.expression.StringLiteral)

Example 5 with JpqlFunction

use of com.blazebit.persistence.spi.JpqlFunction in project blaze-persistence by Blazebit.

the class EclipseLinkEntityManagerIntegrator method getRegisteredFunctions.

@Override
public Map<String, JpqlFunction> getRegisteredFunctions(EntityManagerFactory entityManagerFactory) {
    AbstractSession session = entityManagerFactory.unwrap(JpaEntityManagerFactory.class).getDatabaseSession();
    DatabasePlatform platform = session.getPlatform();
    @SuppressWarnings("unchecked") Map<Integer, ExpressionOperator> platformOperators = platform.getPlatformOperators();
    Map<String, JpqlFunction> functions = new HashMap<>(platformOperators.size());
    for (ExpressionOperator op : platformOperators.values()) {
        String name = (String) ExpressionOperator.getPlatformOperatorNames().get(op.getSelector());
        if (name != null) {
            if (op instanceof JpqlFunctionExpressionOperator) {
                functions.put(name.toLowerCase(), ((JpqlFunctionExpressionOperator) op).unwrap());
            } else {
                int selector = op.getSelector();
                // No support for these expressions
                if (selector != ExpressionOperator.Union && selector != ExpressionOperator.UnionAll && selector != ExpressionOperator.Intersect && selector != ExpressionOperator.IntersectAll && selector != ExpressionOperator.Except && selector != ExpressionOperator.ExceptAll) {
                    functions.put(name.toLowerCase(), new ExpressionOperatorJpqlFunction(op));
                }
            }
        }
    }
    // Eclipselink doesn't report all functions..
    functions.put("count", new ExpressionOperatorJpqlFunction(ExpressionOperator.count()));
    functions.put("sum", new ExpressionOperatorJpqlFunction(ExpressionOperator.sum()));
    functions.put("avg", new ExpressionOperatorJpqlFunction(ExpressionOperator.average()));
    functions.put("max", new ExpressionOperatorJpqlFunction(ExpressionOperator.maximum()));
    functions.put("min", new ExpressionOperatorJpqlFunction(ExpressionOperator.minimum()));
    functions.put("stddev", new ExpressionOperatorJpqlFunction(ExpressionOperator.standardDeviation()));
    functions.put("var", new ExpressionOperatorJpqlFunction(ExpressionOperator.variance()));
    return functions;
}
Also used : JpqlFunction(com.blazebit.persistence.spi.JpqlFunction) HashMap(java.util.HashMap) DatabasePlatform(org.eclipse.persistence.platform.database.DatabasePlatform) ExpressionOperator(org.eclipse.persistence.expressions.ExpressionOperator) JpaEntityManagerFactory(org.eclipse.persistence.jpa.JpaEntityManagerFactory) AbstractSession(org.eclipse.persistence.internal.sessions.AbstractSession)

Aggregations

JpqlFunction (com.blazebit.persistence.spi.JpqlFunction)12 HashMap (java.util.HashMap)8 JpqlFunctionGroup (com.blazebit.persistence.spi.JpqlFunctionGroup)5 Map (java.util.Map)5 StoreManager (org.datanucleus.store.StoreManager)4 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)4 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)4 CountStarFunction (com.blazebit.persistence.integration.jpa.function.CountStarFunction)3 EntityManager (javax.persistence.EntityManager)3 SQLMethod (org.datanucleus.store.rdbms.sql.method.SQLMethod)3 IOException (java.io.IOException)2 Constructor (java.lang.reflect.Constructor)2 TreeMap (java.util.TreeMap)2 NucleusContext (org.datanucleus.NucleusContext)2 QueryGenerator (org.datanucleus.store.rdbms.query.QueryGenerator)2 SQLStatement (org.datanucleus.store.rdbms.sql.SQLStatement)2 ExpressionOperator (org.eclipse.persistence.expressions.ExpressionOperator)2 AbstractSession (org.eclipse.persistence.internal.sessions.AbstractSession)2 JpaEntityManagerFactory (org.eclipse.persistence.jpa.JpaEntityManagerFactory)2 DatabasePlatform (org.eclipse.persistence.platform.database.DatabasePlatform)2