Search in sources :

Example 1 with ValuesStrategy

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

the class AbstractCommonQueryBuilder method getEntityFunctionNodes.

protected List<EntityFunctionNode> getEntityFunctionNodes(Query baseQuery, List<JoinNode> valuesNodes, List<JoinNode> lateInlineNodes, boolean filterNulls) {
    List<EntityFunctionNode> entityFunctionNodes = new ArrayList<>();
    DbmsDialect dbmsDialect = mainQuery.dbmsDialect;
    ValuesStrategy strategy = dbmsDialect.getValuesStrategy();
    String dummyTable = dbmsDialect.getDummyTable();
    for (JoinNode node : valuesNodes) {
        Class<?> clazz = node.getInternalEntityType().getJavaType();
        String valueClazzAttributeName = node.getValuesLikeAttribute();
        int valueCount = node.getValueCount();
        boolean identifiableReference = node.getNodeType() instanceof EntityType<?> && node.getValuesIdNames() != null;
        String rootAlias = node.getAlias();
        String castedParameter = node.getValuesCastedParameter();
        String[] attributes = node.getValuesAttributes();
        // We construct an example query representing the values clause with a SELECT clause that selects the fields in the right order which we need to construct SQL
        // that uses proper aliases and filters null values which are there in the first place to pad up parameters in case we don't reach the desired value count
        StringBuilder valuesSb = new StringBuilder(20 + valueCount * attributes.length * 3);
        Query valuesExampleQuery = getValuesExampleQuery(clazz, valueCount, identifiableReference, valueClazzAttributeName, rootAlias, castedParameter, attributes, valuesSb, strategy, dummyTable, node);
        String exampleQuerySql = mainQuery.cbf.getExtendedQuerySupport().getSql(mainQuery.em, valuesExampleQuery);
        String exampleQuerySqlAlias = mainQuery.cbf.getExtendedQuerySupport().getSqlAlias(mainQuery.em, valuesExampleQuery, "e");
        String exampleQueryCollectionSqlAlias = null;
        if (!node.isValueClazzAttributeSingular()) {
            exampleQueryCollectionSqlAlias = mainQuery.cbf.getExtendedQuerySupport().getSqlAlias(mainQuery.em, valuesExampleQuery, node.getValueClazzAlias("e_"));
        }
        StringBuilder whereClauseSb = new StringBuilder(exampleQuerySql.length());
        String filterNullsTableAlias = "fltr_nulls_tbl_als_";
        String valuesAliases = getValuesAliases(exampleQuerySqlAlias, attributes.length, exampleQuerySql, whereClauseSb, filterNullsTableAlias, strategy, dummyTable);
        if (strategy == ValuesStrategy.SELECT_VALUES) {
            valuesSb.insert(0, valuesAliases);
            valuesSb.append(')');
            valuesAliases = null;
        } else if (strategy == ValuesStrategy.SELECT_UNION) {
            valuesSb.insert(0, valuesAliases);
            if (!filterNulls) {
                // We must order by all values and use a limit in such a case
                valuesSb.insert(0, "(select * from ");
                valuesSb.append(") val_tmp_ order by ");
                if (dbmsDialect.isNullSmallest()) {
                    for (int i = 0; i < attributes.length; i++) {
                        valuesSb.append(i + 1);
                        valuesSb.append(',');
                    }
                } else {
                    for (int i = 0; i < attributes.length; i++) {
                        dbmsDialect.appendOrderByElement(valuesSb, new DefaultOrderByElement(null, i + 1, true, true, true), null);
                        valuesSb.append(',');
                    }
                }
                valuesSb.setCharAt(valuesSb.length() - 1, ' ');
                dbmsDialect.appendExtendedSql(valuesSb, DbmsStatementType.SELECT, false, true, null, Integer.toString(valueCount + 1), "1", null, null, null);
            }
            valuesSb.append(')');
            valuesAliases = null;
        }
        if (filterNulls) {
            valuesSb.insert(0, "(select * from ");
            valuesSb.append(' ');
            valuesSb.append(filterNullsTableAlias);
            if (valuesAliases != null) {
                valuesSb.append(valuesAliases);
                valuesAliases = null;
            }
            valuesSb.append(whereClauseSb);
            valuesSb.append(')');
        }
        String valuesClause = valuesSb.toString();
        String valuesTableSqlAlias = exampleQuerySqlAlias;
        String valuesTableJoin = null;
        String pluralCollectionTableAlias = null;
        String pluralTableAlias = null;
        String syntheticPredicate = exampleQuerySql.substring(SqlUtils.indexOfWhere(exampleQuerySql) + " where ".length());
        if (baseQuery != null) {
            valuesTableSqlAlias = cbf.getExtendedQuerySupport().getSqlAlias(em, baseQuery, node.getAlias());
            syntheticPredicate = syntheticPredicate.replace(exampleQuerySqlAlias, valuesTableSqlAlias);
            if (exampleQueryCollectionSqlAlias != null) {
                pluralTableAlias = cbf.getExtendedQuerySupport().getSqlAlias(em, baseQuery, node.getValueClazzAlias(node.getAlias() + "_"));
                syntheticPredicate = syntheticPredicate.replace(exampleQueryCollectionSqlAlias, pluralTableAlias);
                String baseQuerySql = cbf.getExtendedQuerySupport().getSql(em, baseQuery);
                int[] indexRange = SqlUtils.indexOfFullJoin(baseQuerySql, pluralTableAlias);
                String baseTableAlias = " " + valuesTableSqlAlias + " ";
                int baseTableAliasIndex = baseQuerySql.indexOf(baseTableAlias);
                int fullJoinStartIndex = baseTableAliasIndex + baseTableAlias.length();
                if (fullJoinStartIndex != indexRange[0]) {
                    // TODO: find out pluralCollectionTableAlias
                    String onClause = " on ";
                    int onClauseIndex = baseQuerySql.indexOf(onClause, fullJoinStartIndex);
                    int[] collectionTableIndexRange = SqlUtils.rtrimBackwardsToFirstWhitespace(baseQuerySql, onClauseIndex);
                    pluralCollectionTableAlias = baseQuerySql.substring(collectionTableIndexRange[0], collectionTableIndexRange[1]);
                }
                valuesTableJoin = baseQuerySql.substring(fullJoinStartIndex, indexRange[1]);
            }
        }
        entityFunctionNodes.add(new EntityFunctionNode(valuesClause, valuesAliases, node.getInternalEntityType().getName(), valuesTableSqlAlias, pluralCollectionTableAlias, pluralTableAlias, valuesTableJoin, syntheticPredicate, false));
    }
    // We assume to have to select via a union to apply aliases correctly when the values strategy requires that
    boolean selectUnion = strategy == ValuesStrategy.SELECT_UNION;
    boolean lateralStyle = dbmsDialect.getLateralStyle() == LateralStyle.LATERAL;
    for (JoinNode lateInlineNode : lateInlineNodes) {
        CTEInfo cteInfo = lateInlineNode.getInlineCte();
        String aliases;
        StringBuilder aliasesSb = new StringBuilder();
        if (selectUnion) {
            aliasesSb.append("select ");
            for (int i = 0; i < cteInfo.columnNames.size(); i++) {
                aliasesSb.append("null ");
                aliasesSb.append(cteInfo.columnNames.get(i)).append(',');
            }
            aliasesSb.setCharAt(aliasesSb.length() - 1, ' ');
            aliasesSb.append(" from ").append(dummyTable).append(" where 1=0 union all ");
            aliases = null;
        } else {
            aliasesSb.append('(');
            for (int i = 0; i < cteInfo.columnNames.size(); i++) {
                aliasesSb.append(cteInfo.columnNames.get(i)).append(',');
            }
            aliasesSb.setCharAt(aliasesSb.length() - 1, ')');
            aliases = aliasesSb.toString();
            aliasesSb = null;
        }
        String subquery;
        if (lateInlineNode.isLateral()) {
            // We need to wrap the lateral subquery into a temporary HQL subquery to fake the correlation
            // Then, we extract the sql part of the actual subquery
            StringBuilder lateralExampleQueryString = new StringBuilder();
            buildLateralExampleQueryString(lateralExampleQueryString);
            String sql = getQuerySpecification(cteInfo.nonRecursiveCriteriaBuilder.getLateralQuery(lateralExampleQueryString, lateralStyle ? null : lateInlineNode)).getSql();
            int start = SqlUtils.indexOfWhere(sql);
            while (sql.charAt(start) != '(') {
                start++;
            }
            String prefix;
            if (dbmsDialect.getLateralStyle() == LateralStyle.LATERAL) {
                prefix = "lateral (";
            } else if (lateInlineNode.getJoinType() == JoinType.INNER) {
                prefix = "cross apply (";
            } else {
                prefix = "outer apply (";
            }
            if (aliasesSb == null) {
                subquery = prefix + sql.substring(start + 1, sql.lastIndexOf(')')) + ")";
            } else {
                aliasesSb.insert(0, prefix).append('(').append(sql, start + 1, sql.lastIndexOf(')')).append(')').append(')');
                subquery = aliasesSb.toString();
            }
        } else {
            if (aliasesSb == null) {
                subquery = "(" + getQuerySpecification(cteInfo.nonRecursiveCriteriaBuilder.getQuery()).getSql() + ")";
            } else {
                aliasesSb.insert(0, "(").append('(').append(getQuerySpecification(cteInfo.nonRecursiveCriteriaBuilder.getQuery()).getSql()).append(')').append(')');
                subquery = aliasesSb.toString();
            }
        }
        String cteTableSqlAlias = baseQuery == null ? "" : cbf.getExtendedQuerySupport().getSqlAlias(em, baseQuery, lateInlineNode.getAlias());
        entityFunctionNodes.add(new EntityFunctionNode(subquery, aliases, cteInfo.cteType.getName(), cteTableSqlAlias, null, null, null, null, lateInlineNode.isLateral()));
    }
    return entityFunctionNodes;
}
Also used : CustomSQLTypedQuery(com.blazebit.persistence.impl.query.CustomSQLTypedQuery) AbstractCustomQuery(com.blazebit.persistence.impl.query.AbstractCustomQuery) TypedQuery(javax.persistence.TypedQuery) CustomSQLQuery(com.blazebit.persistence.impl.query.CustomSQLQuery) Query(javax.persistence.Query) ObjectBuilderTypedQuery(com.blazebit.persistence.impl.query.ObjectBuilderTypedQuery) DbmsDialect(com.blazebit.persistence.spi.DbmsDialect) ArrayList(java.util.ArrayList) ValuesStrategy(com.blazebit.persistence.spi.ValuesStrategy) EntityFunctionNode(com.blazebit.persistence.impl.query.EntityFunctionNode)

Aggregations

AbstractCustomQuery (com.blazebit.persistence.impl.query.AbstractCustomQuery)1 CustomSQLQuery (com.blazebit.persistence.impl.query.CustomSQLQuery)1 CustomSQLTypedQuery (com.blazebit.persistence.impl.query.CustomSQLTypedQuery)1 EntityFunctionNode (com.blazebit.persistence.impl.query.EntityFunctionNode)1 ObjectBuilderTypedQuery (com.blazebit.persistence.impl.query.ObjectBuilderTypedQuery)1 DbmsDialect (com.blazebit.persistence.spi.DbmsDialect)1 ValuesStrategy (com.blazebit.persistence.spi.ValuesStrategy)1 ArrayList (java.util.ArrayList)1 Query (javax.persistence.Query)1 TypedQuery (javax.persistence.TypedQuery)1