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;
}
Aggregations