Skip to content

Commit

Permalink
RD-9079: Records with duplicate fields names (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
bgaidioz authored Aug 9, 2023
1 parent 426b293 commit 576e5d5
Show file tree
Hide file tree
Showing 18 changed files with 186 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,11 @@ object JsonRecurse {
val childRootNode = new ProgramStatementNode(lang, frameDescriptor, child)
new IterableWriteJsonNode(childRootNode)
case Rql2RecordType(atts, _) =>
val fieldNamesMap = new util.HashMap[String, Integer]
val children = atts.zipWithIndex.map {
case (att, idx) =>
fieldNamesMap.put(att.idn, idx)
val child = recurse(att.tipe.asInstanceOf[Rql2TypeWithProperties], isSafe = true)
new ProgramStatementNode(lang, frameDescriptor, child)
val children = atts.map { att =>
val child = recurse(att.tipe.asInstanceOf[Rql2TypeWithProperties], isSafe = true)
new ProgramStatementNode(lang, frameDescriptor, child)
}.toArray
new RecordWriteJsonNode(children, fieldNamesMap)
new RecordWriteJsonNode(children)
case Rql2ByteType(_) => new ByteWriteJsonNode()
case Rql2ShortType(_) => new ShortWriteJsonNode()
case Rql2IntType(_) => new IntWriteJsonNode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import raw.testing.tags.TruffleTests
@TruffleTests class RD7974TruffleTest extends TruffleCompilerTestContext with RD7974Test

// RD-9079 (duplicate record fields)
// class RD5714TruffleTest extends TruffleCompilerTestContext with RD5714Test
@TruffleTests class RD5714TruffleTest extends TruffleCompilerTestContext with RD5714Test

// XML
// class RD5697TruffleTest extends TruffleCompilerTestContext with RD5697Test
Expand Down Expand Up @@ -101,7 +101,7 @@ import raw.testing.tags.TruffleTests
@TruffleTests class RD5365TruffleTest extends TruffleCompilerTestContext with RD5365Test

// RD-9079 (records with duplicate fields not supported)
// class RD5914TruffleTest extends TruffleCompilerTestContext with RD5914Test
@TruffleTests class RD5914TruffleTest extends TruffleCompilerTestContext with RD5914Test

@TruffleTests class RD9137TruffleTest extends TruffleCompilerTestContext with RD9137Test
@TruffleTests class RD9228TruffleTest extends TruffleCompilerTestContext with RD9228Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ trait Rql2OutputTestContext {
// }
// throw new AssertionError("couldn't parse OrType with any parser")
case Rql2RecordType(atts, _) if n.isObject =>
// TODO (msb): Validate it's the actual type complying with our format
val m = mutable.LinkedHashMap[String, Any]()
atts.foreach { case Rql2AttrType(idn, t1) => m.put(idn, recurse(n.get(idn), t1)) }
m
val fields = n.fields().asScala.toVector
val tipes = atts.map(_.tipe)
assert(fields.length == tipes.length)
fields.zip(tipes).map { case (p, t) => p.getKey -> recurse(p.getValue, t) }
case _: Rql2ListType | _: Rql2IterableType if n.isArray =>
val inner = t match {
case Rql2ListType(inner, _) => inner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ trait JsonOutputTest extends CompilerTestContext {
val path: Path = Files.createTempFile("", "")
try {
it should saveToInFormat(path, "json")
assume(language != "rql2-truffle")
// fields 'a' are renamed as 'a', 'a_1' and 'a_2'
path should contain("""{"a":1,"b":2,"a_1":3,"c":4,"a_2":5}""")
} finally {
Expand All @@ -73,7 +72,6 @@ trait JsonOutputTest extends CompilerTestContext {
val path: Path = Files.createTempFile("", "")
try {
it should saveToInFormat(path, "json")
assume(language != "rql2-truffle") // duplicated fields not done in rql2-truffle yet
// fields 'a' are renamed as 'a', 'a_2' because 'a_1' exists already
path should contain("""{"a":1,"b":2,"a_2":3,"c":4,"a_1":5}""")
} finally {
Expand All @@ -86,7 +84,6 @@ trait JsonOutputTest extends CompilerTestContext {
val path: Path = Files.createTempFile("", "")
try {
it should saveToInFormat(path, "json")
assume(language != "rql2-truffle") // duplicated fields not done in rql2-truffle yet
// fields 'a' are renamed as 'a', 'a_2' because 'a_1' exists already
path should contain("""{"a_1":1,"b":2,"a":3,"c":4,"a_2":5}""")
} finally {
Expand All @@ -99,7 +96,6 @@ trait JsonOutputTest extends CompilerTestContext {
val path: Path = Files.createTempFile("", "")
try {
it should saveToInFormat(path, "json")
assume(language != "rql2-truffle") // duplicated fields not done in rql2-truffle yet
path should contain("""{"a":1,"b":2,"a_3":3,"c":4,"a_2":5,"a_1":6}""")
} finally {
RawUtils.deleteTestPath(path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ trait RD3084Test extends CompilerTestContext with RDBMSTestCreds {
// switching the order of the fields
test("""MySQL.Query("mysql-test", "select * from test_types",
| type collection(record(char1: string, integer1: int)))""".stripMargin) {
_ should evaluateTo("""[{integer1: 1, char1: "string"}]""")
_ should evaluateTo("""[{char1: "string", integer1: 1}]""")
}

test("""PostgreSQL.InferAndQuery("postgres-test", "select * from rdbmstest.test_types")""") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@ trait RD5714Test extends CompilerTestContext {
| colB = [{id: 2, firstName: "john"}],
| join = List.Join(colA, colB, i -> i.name == i.firstName)
|in Json.Print(join)""".stripMargin) { it =>
if (language == "rql2-truffle") {
// rql2-truffle fixes duplicated fields as part of RD-9079
it should evaluateTo(""" "[{\"id\":1,\"name\":\"john\",\"id\":2,\"firstName\":\"john\"}]" """.stripMargin)
} else {
it should evaluateTo(""" "[{\"id\":1,\"name\":\"john\",\"id_1\":2,\"firstName\":\"john\"}]" """.stripMargin)
}
it should evaluateTo(""" "[{\"id\":1,\"name\":\"john\",\"id_1\":2,\"firstName\":\"john\"}]" """.stripMargin)
}

test("""let colA = [{id: 1, name: "john"}],
Expand All @@ -45,11 +40,7 @@ trait RD5714Test extends CompilerTestContext {
} finally {
source.close()
}
if (language == "rql2-truffle") {
assert(s == """[{"id":1,"name":"john","id":2,"firstName":"john"}]""")
} else {
assert(s == """[{"id":1,"name":"john","id_1":2,"firstName":"john"}]""")
}
assert(s == """[{"id":1,"name":"john","id_1":2,"firstName":"john"}]""")
} finally {
Files.delete(path)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ trait RD5914Test extends CompilerTestContext {
test("""let item1 = {name: "coffee machine", price: 200, price: 199}, // price is duplicated, price is an int
| item2 = {name: "coffee machine", price: 200.00, price: 199.99} // price is duplicated, price is a double
|in [item1, item2] // item1 integer fields have to be cast to double
|""".stripMargin)(_ should run)
|""".stripMargin)(_ should evaluateTo("""[{name: "coffee machine", price: 200.0, price: 199.0},
|{name: "coffee machine", price: 200.00, price: 199.99}
|]""".stripMargin))

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ trait RD9228Test extends CompilerTestContext {

// Declare the location as a variable. Json.Read has to resolve its value dynamically using a walk through frames.
// Because we read a tryable (list), the tryable handler is involved. It didn't expect the nested read to have a
// free variable.
// free variable (RD-9329).
test("""
|let location = Http.Get("https://raw-tutorial.s3.eu-west-1.amazonaws.com/trips.json")
|in Json.Read(location, type list(record(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.instrumentation.ProvidedTags;
import com.oracle.truffle.api.instrumentation.StandardTags;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.api.nodes.Node;
import raw.runtime.truffle.runtime.record.RecordObject;

Expand All @@ -27,12 +26,6 @@ public final class RawLanguage extends TruffleLanguage<RawContext> {
public static final String VERSION = "0.10";
public static final String MIME_TYPE = "application/x-rql";

private final Shape rootRecordShape;

public RawLanguage() {
this.rootRecordShape = Shape.newBuilder().layout(RecordObject.class).build();
}

@Override
protected final RawContext createContext(Env env) {
return new RawContext(this, env);
Expand All @@ -50,11 +43,7 @@ public static RawLanguage get(Node node) {
}

public RecordObject createRecord() {
return new RecordObject(rootRecordShape);
}

public RecordObject createRecord(Shape shape) {
return new RecordObject(shape);
return new RecordObject();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.*;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.NodeInfo;
import raw.runtime.truffle.ExpressionNode;
import raw.runtime.truffle.RawLanguage;
Expand All @@ -28,24 +27,22 @@
@NodeChild("valueNode")
public abstract class RecordAddFieldNode extends ExpressionNode {

@Specialization(limit = "3")
protected Object doAddField(Object record, String newKey, Object newValue,
@CachedLibrary("record") InteropLibrary records,
@CachedLibrary(limit = "2") InteropLibrary libraries) {
@Specialization
protected Object doAddField(Object rec, String newKey, Object newValue) {
RecordObject record = (RecordObject) rec;
RecordObject newRecord = RawLanguage.get(this).createRecord();
try {
Object keys = records.getMembers(record);
long length = libraries.getArraySize(keys);
String member;
for (int i = 0; i < length; i++) {
member = (String) libraries.readArrayElement(keys, i);
libraries.writeMember(newRecord, member, records.readMember(record, member));
String[] keys = record.keys();
int length = keys.length;
String member;
for (int i = 0; i < length; i++) {
member = keys[i];
try {
newRecord.writeIdx(i, member, record.readIdx(i));
} catch (InvalidArrayIndexException e) {
throw new RawTruffleInternalErrorException(e, this);
}
libraries.writeMember(newRecord, newKey, newValue);
return newRecord;
} catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException |
InvalidArrayIndexException e) {
throw new RawTruffleInternalErrorException(e, this);
}
newRecord.writeIdx(length, newKey, newValue);
return newRecord;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.NodeInfo;
import raw.runtime.truffle.ExpressionNode;
import raw.runtime.truffle.RawLanguage;
import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException;
import raw.runtime.truffle.runtime.record.RecordObject;

@NodeInfo(shortName = "Record.Build")
Expand All @@ -47,15 +43,11 @@ public RecordBuildNode(ExpressionNode[] elementsNodes) {
@Override
public RecordObject executeGeneric(VirtualFrame frame) {
RecordObject record = RawLanguage.get(this).createRecord();
try {
for (int i = 0, j = 0; i < elementNodes.length; i += 2, j++) {
// i jump by 2 because we have k1, v1, k2, v2, ..., kn, vn.
Object key = elementNodes[i].executeGeneric(frame);
Object value = elementNodes[i + 1].executeGeneric(frame);
libraries.writeMember(record, (String) key, value);
}
} catch (UnknownIdentifierException | UnsupportedMessageException | UnsupportedTypeException e) {
throw new RawTruffleInternalErrorException(e, this);
for (int i = 0, j = 0; i < elementNodes.length; i += 2, j++) {
// i jump by 2 because we have k1, v1, k2, v2, ..., kn, vn.
Object key = elementNodes[i].executeGeneric(frame);
Object value = elementNodes[i + 1].executeGeneric(frame);
record.writeIdx(j, (String) key, value);
}
return record;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.*;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.NodeInfo;
import raw.runtime.truffle.ExpressionNode;
import raw.runtime.truffle.RawLanguage;
Expand All @@ -28,28 +27,26 @@
public abstract class RecordConcatNode extends ExpressionNode {

@Specialization(limit = "3")
protected Object doConcat(Object record1, Object record2,
@CachedLibrary("record1") InteropLibrary records1,
@CachedLibrary("record2") InteropLibrary records2,
@CachedLibrary(limit = "3") InteropLibrary libraries) {
protected Object doConcat(Object rec1, Object rec2) {
RecordObject newRecord = RawLanguage.get(this).createRecord();
RecordObject record1 = (RecordObject) rec1;
RecordObject record2 = (RecordObject) rec2;
try {
Object keys1 = records1.getMembers(record1);
Object keys2 = records2.getMembers(record2);
long length1 = libraries.getArraySize(keys1);
long length2 = libraries.getArraySize(keys2);
String[] keys1 = record1.keys();
String[] keys2 = record2.keys();
int length1 = keys1.length;
int length2 = keys2.length;
String member;
for (int i = 0; i < length1; i++) {
member = (String) libraries.readArrayElement(keys1, i);
libraries.writeMember(newRecord, member, records1.readMember(record1, member));
member = keys1[i];
newRecord.writeIdx(i, member, record1.readIdx(i));
}
for (int i = 0; i < length2; i++) {
member = (String) libraries.readArrayElement(keys2, i);
libraries.writeMember(newRecord, member, records2.readMember(record2, member));
member = keys2[i];
newRecord.writeIdx(i + length1, member, record2.readIdx(i));
}
return newRecord;
} catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException |
InvalidArrayIndexException e) {
} catch (InvalidArrayIndexException e) {
throw new RawTruffleInternalErrorException(e, this);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,32 @@

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.NodeInfo;
import raw.runtime.truffle.ExpressionNode;
import raw.runtime.truffle.runtime.exceptions.RawTruffleInternalErrorException;
import raw.runtime.truffle.runtime.record.RecordObject;

@NodeInfo(shortName = "Record.Project")
@NodeChild("receiverNode")
@NodeChild("indexNode")
public abstract class RecordProjNode extends ExpressionNode {

@Specialization(limit = "3")
protected Object readMember(Object record, String key,
@CachedLibrary("record") InteropLibrary records) {
protected Object readMember(RecordObject record, String key) {
try {
return records.readMember(record, key);
} catch (UnsupportedMessageException | UnknownIdentifierException e) {
return record.readByKey(key);
} catch (UnknownIdentifierException e) {
throw new RawTruffleInternalErrorException(e, this);
}
}

@Specialization(limit = "3")
protected Object readMember(Object record, int index,
@CachedLibrary("record") InteropLibrary records,
@CachedLibrary(limit = "1") InteropLibrary libraries) {
@Specialization
protected Object readMember(RecordObject record, int index) {
try {
Object keys = records.getMembers(record);
String member = (String) libraries.readArrayElement(keys, index - 1);
return records.readMember(record, member);
} catch (UnsupportedMessageException | UnknownIdentifierException | InvalidArrayIndexException e) {
return record.readIdx(index - 1);
} catch (InvalidArrayIndexException e) {
throw new RawTruffleInternalErrorException(e, this);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,7 @@ public Object executeGeneric(VirtualFrame frame) {
String fieldName = columns[i].idn();
parser.getNextField();
Object value = childDirectCalls[i].call(parser);
try {
records.writeMember(record, fieldName, value);
} catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException ex) {
throw new RawTruffleInternalErrorException(ex, this);
}
record.writeIdx(i, fieldName, value);
}
parser.finishLine(this);
return record;
Expand Down
Loading

0 comments on commit 576e5d5

Please sign in to comment.