Skip to content

Commit

Permalink
The generated join classes should only use the Nullable annotation wh…
Browse files Browse the repository at this point in the history
…en the joined column is part of an outer join.
  • Loading branch information
broneill committed Sep 12, 2024
1 parent bb2c743 commit f06dacd
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/main/java/org/cojen/tupl/core/TupleKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public abstract static class Maker {

public abstract TupleKey with(Object[] e0, Object e1);

public abstract TupleKey with(Object[] e0, Object[] e1);
public abstract TupleKey with(Object[] e0);

static CallSite indyWith(MethodHandles.Lookup lookup, String name, MethodType mt) {
MethodMaker mm = MethodMaker.begin(lookup, name, mt);
Expand Down
25 changes: 19 additions & 6 deletions src/main/java/org/cojen/tupl/table/join/JoinSpec.java
Original file line number Diff line number Diff line change
Expand Up @@ -664,14 +664,18 @@ void appendTo(StringBuilder b) {
public static sealed class Column extends Node implements Source {
private final Table mTable;
private final ColumnInfo mColumn;
private final boolean mDefined;

private boolean mNullable;

Column(Table table, ColumnInfo column, boolean nullable) {
Column(Table table, ColumnInfo column, boolean defined, boolean nullable) {
mTable = table;
mColumn = column;
mDefined = defined;
mNullable = nullable;
nullableCheck();
if (!defined) {
nullableCheck();
}
}

@Override
Expand Down Expand Up @@ -824,8 +828,14 @@ boolean isEmpty() throws IOException {

@Override
void nullable() {
mNullable = true;
nullableCheck();
if (!mNullable) {
mNullable = true;
if (mDefined) {
mColumn.typeCode |= ColumnInfo.TYPE_NULLABLE;
} else {
nullableCheck();
}
}
}

@Override
Expand Down Expand Up @@ -864,7 +874,7 @@ public static final class PlannedColumn extends Column implements Cloneable {
private long mFilterScore;

PlannedColumn(Column column) {
super(column.mTable, column.mColumn, column.mNullable);
super(column.mTable, column.mColumn, column.mDefined, column.mNullable);
}

@Override
Expand Down Expand Up @@ -1529,13 +1539,15 @@ private Node parseSource(boolean nullable) throws IOException {
String name = mText.substring(start, --mPos);

ColumnInfo column;
boolean defined;

if (mAllColumns != null) {
column = mAllColumns.get(name);
if (column == null) {
mPos = start;
throw error("Unknown column");
}
defined = false;
} else {
if (mNumTables >= mTables.length) {
throw new IllegalArgumentException("Not enough tables provided");
Expand All @@ -1544,6 +1556,7 @@ private Node parseSource(boolean nullable) throws IOException {
column.name = name;
column.type = mTables[mNumTables].rowType();
column.typeCode = ColumnInfo.TYPE_REFERENCE;
defined = true;
}

if (mSelectedColumns.putIfAbsent(name, column) != null) {
Expand All @@ -1568,7 +1581,7 @@ private Node parseSource(boolean nullable) throws IOException {

mNumTables++;

return new Column(table, column, nullable);
return new Column(table, column, defined, nullable);
}

/**
Expand Down
26 changes: 17 additions & 9 deletions src/main/java/org/cojen/tupl/table/join/JoinTableMaker.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,12 @@ private static Class<Row> makeJoinTypeClass(Map<String, ColumnInfo> columns) {
cm.sourceFile(JoinTableMaker.class.getSimpleName());

for (ColumnInfo ci : columns.values()) {
cm.addMethod(ci.type, ci.name).public_().abstract_()
.addAnnotation(Nullable.class, true);
MethodMaker mm = cm.addMethod(ci.type, ci.name).public_().abstract_();

if (ci.isNullable()) {
mm.addAnnotation(Nullable.class, true);
}

cm.addMethod(null, ci.name, ci.type).public_().abstract_();
}

Expand All @@ -112,16 +116,20 @@ public static JoinTable<Row> join(String specStr, Table<?>... tables) {

TupleKey cacheKey;
{
var names = new String[definedColumns.size()];
var types = new Class[names.length];
var pairs = new Object[definedColumns.size() * 2];
int i = 0;
for (ColumnInfo column : definedColumns.values()) {
names[i] = column.name;
types[i] = column.type;
i++;
String name = column.name.intern();
if (column.isNullable()) {
pairs[i++] = name;
pairs[i++] = column.type;
} else {
pairs[i++] = column.type;
pairs[i++] = name;
}
}
assert i == names.length;
cacheKey = TupleKey.make.with(names, types, definedColumns);
assert i == pairs.length;
cacheKey = TupleKey.make.with(pairs);
}

return join(cTypeCache.obtain(cacheKey, definedColumns), spec);
Expand Down

0 comments on commit f06dacd

Please sign in to comment.