Skip to content

Commit

Permalink
Fix grouped order by spec.
Browse files Browse the repository at this point in the history
  • Loading branch information
broneill committed Jul 29, 2024
1 parent 4150767 commit 9d89d79
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 44 deletions.
65 changes: 34 additions & 31 deletions src/main/java/org/cojen/tupl/table/expr/GroupedQueryExpr.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,31 @@ static GroupedQueryExpr make(int startPos, int endPos, RelationType type,
List<ProjExpr> projection, int groupBy,
int maxArgument, String orderBy)
{
String groupBySpec, groupOrderBySpec;

{
var b = new StringBuilder();
for (int i=0; i<groupBy; i++) {
projection.get(i).appendToOrderBySpec(b);
}
groupBySpec = b.isEmpty() ? "" : b.toString().intern();

b.setLength(0);

for (int i=groupBy; i<projection.size(); i++) {
ProjExpr pe = projection.get(i);
if (pe.isGrouping()) {
break;
}
if (pe.hasOrderBy()) {
pe.appendToOrderBySpec(b);
}
}

groupOrderBySpec = b.isEmpty() ? "" : b.toString().intern();

}

var newAssignments = new HashMap<ColumnExpr, AssignExpr>();

if (filter != null) {
Expand All @@ -81,23 +106,29 @@ static GroupedQueryExpr make(int startPos, int endPos, RelationType type,
(i, proj) -> proj.asWindow(newAssignments));

return new GroupedQueryExpr(startPos, endPos, type, from, rowFilter, filter,
projection, groupBy, maxArgument, orderBy);
projection, groupBy, maxArgument, orderBy,
groupBySpec, groupOrderBySpec);
}

private final int mNumGroupBy;
private final Expr mFilter;
private final String mOrderBy;
private final String mGroupBySpec;
private final String mGroupOrderBySpec;

private GroupedQueryExpr(int startPos, int endPos, RelationType type,
RelationExpr from, RowFilter rowFilter, Expr filter,
List<ProjExpr> projection, int groupBy,
int maxArgument, String orderBy)
int maxArgument, String orderBy,
String groupBySpec, String groupOrderBySpec)
{
super(startPos, endPos, type, from, rowFilter, projection, maxArgument);

mNumGroupBy = groupBy;
mFilter = filter;
mOrderBy = orderBy;
mGroupBySpec = groupBySpec;
mGroupOrderBySpec = groupOrderBySpec;
}

@Override
Expand Down Expand Up @@ -158,15 +189,12 @@ public CompiledQuery makeCompiledQuery() throws IOException {

QueryGrouper qg = cCache.obtain(makeKey(), this);

String groupBySpec = groupBySpec();
String groupOrderBySpec = groupOrderBySpec();

Class targetClass = rowTypeClass();

int argCount = maxArgument();

if (argCount == 0) {
Table table = source.table().group(groupBySpec, groupOrderBySpec,
Table table = source.table().group(mGroupBySpec, mGroupOrderBySpec,
targetClass, qg.factoryFor(RowUtils.NO_ARGS));
if (mOrderBy != null) {
table = table.view(mOrderBy);
Expand All @@ -187,31 +215,6 @@ public CompiledQuery makeCompiledQuery() throws IOException {
throw null;
}

private String groupBySpec() {
var b = new StringBuilder();

for (int i=0; i<mNumGroupBy; i++) {
mProjection.get(i).appendToOrderBySpec(b);
}

return b.isEmpty() ? "" : b.toString().intern();
}

private String groupOrderBySpec() {
// FIXME: Doesn't work when ProjExpr wraps a AssignExpr or VarExpr.

var b = new StringBuilder();

for (int i=mNumGroupBy; i<mProjection.size(); i++) {
ProjExpr pe = mProjection.get(i);
if (pe.hasOrderBy()) {
pe.appendToOrderBySpec(b);
}
}

return b.isEmpty() ? "" : b.toString().intern();
}

private QueryGrouper makeQueryGrouper() {
Class<?> grouperClass = makeGrouperClass();

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/cojen/tupl/table/expr/ProjExpr.java
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,15 @@ public String toString() {

@Override
public void appendTo(StringBuilder b) {
appendTo(b, false, false);
appendTo(b, false);
}

void appendTo(StringBuilder b, boolean nameOnly, boolean orderBy) {
void appendTo(StringBuilder b, boolean nameOnly) {
if (hasExclude()) {
b.append('~');
}

if (orderBy || hasOrderBy()) {
if (hasOrderBy()) {
b.append(hasDescending() ? '-' : '+');
if (hasNullLow()) {
b.append('!');
Expand Down
36 changes: 26 additions & 10 deletions src/main/java/org/cojen/tupl/table/expr/QueryExpr.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,16 @@ public static RelationExpr make(int startPos, int endPos,
Map<String, ProjExpr> fromProjMap = null;
Map<Expr, ColumnExpr> replacements = null;

for (int i=0; i<groupBy; i++) {
// The loop could just stop when groupBy is reached, but going further allows
// ordering within the group to be examined too. Stop as soon as a projection is
// reached which performs an actual grouping operation.
for (int i=0; i<projection.size(); i++) {
ProjExpr pe = projection.get(i);
if (pe.isGrouping()) {
assert i > groupBy;
break;
}

Expr wrapped = pe.wrapped();
if (wrapped instanceof ColumnExpr) {
continue;
Expand All @@ -97,8 +105,8 @@ public static RelationExpr make(int startPos, int endPos,
fromProjMap.put(name, pe);

ColumnExpr col = ColumnExpr.make
(-1, -1, fromRowType, Column.make(pe.type(), name, false));
projection.set(i, ProjExpr.make(-1, -1, col, pe.flags()));
(pe.startPos(), pe.endPos(), fromRowType, Column.make(pe.type(), name, false));
projection.set(i, ProjExpr.make(pe.startPos(), pe.endPos(), col, pe.flags()));

if (!(wrapped instanceof AssignExpr assign)) {
continue;
Expand All @@ -125,7 +133,7 @@ public static RelationExpr make(int startPos, int endPos,
addColumns(fromRowType, fromProjMap, filter);
}

for (int i=groupBy; i<projection.size(); i++) {
for (int i=0; i<projection.size(); i++) {
ProjExpr pe = projection.get(i).replace(replacements);
projection.set(i, pe);
addColumns(fromRowType, fromProjMap, pe);
Expand Down Expand Up @@ -255,16 +263,25 @@ public static RelationExpr make(int startPos, int endPos,

boolean hasOrderBy = false;
boolean orderByDerived = false;
boolean isGrouping = false;

for (int i=0; i<projection.size(); i++) {
ProjExpr pe = projection.get(i);

for (ProjExpr pe : projection) {
if (pe.hasExclude()) {
int flags = pe.flags() & ~ProjExpr.F_EXCLUDE;
pe.gatherEvalColumns(fromType, fromProjMap, flags, fromProjection::add);
}

// Once the first grouping projection is reached, it and all remaining
// projections are treated as derived if they're also ordered. The conversion
// to a derived projection is performed by the AggregatedQueryExpr and
// GroupedQueryExpr make methods.
isGrouping |= pe.isGrouping();

if (pe.hasOrderBy()) {
hasOrderBy = true;
if (pe.sourceColumn() == null) {
if (pe.sourceColumn() == null || isGrouping) {
orderByDerived = true;
}
}
Expand All @@ -278,11 +295,10 @@ public static RelationExpr make(int startPos, int endPos,

var b = new StringBuilder().append('{').append('*');

for (int i=0; i<projection.size(); i++) {
ProjExpr pe = projection.get(i);
if (i < groupBy || pe.hasOrderBy()) {
for (ProjExpr pe : projection) {
if (pe.hasOrderBy()) {
b.append(", ");
pe.appendTo(b, true, true);
pe.appendTo(b, true);
}
}

Expand Down

0 comments on commit 9d89d79

Please sign in to comment.