diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/BNode.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/BNode.java index e49019643f5..a5e6ff9f005 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/BNode.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/BNode.java @@ -22,6 +22,11 @@ */ public interface BNode extends Resource { + @Override + default Type getValueType() { + return Type.BNODE; + } + @Override default boolean isBNode() { return true; diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/IRI.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/IRI.java index cb99a4d4e5b..3a4f378dd14 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/IRI.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/IRI.java @@ -33,6 +33,11 @@ */ public interface IRI extends Resource { + @Override + default Type getValueType() { + return Type.IRI; + } + @Override default boolean isIRI() { return true; diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Literal.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Literal.java index b261e76061c..22285a0e497 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Literal.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Literal.java @@ -42,6 +42,11 @@ */ public interface Literal extends Value { + @Override + default Type getValueType() { + return Type.LITERAL; + } + @Override default boolean isLiteral() { return true; diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Resource.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Resource.java index 65f540f95ee..125dc0fb754 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Resource.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Resource.java @@ -17,6 +17,12 @@ public interface Resource extends Value { // Empty place holder as common supertype of IRI and BNode + default Type getValueType(){ + if(isIRI()) return Type.IRI; + if(isBNode()) return Type.BNODE; + return Type.TRIPLE; + } + @Override default boolean isResource() { return true; diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Triple.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Triple.java index 29ad625bae7..df52175db88 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Triple.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Triple.java @@ -28,6 +28,11 @@ @Experimental public interface Triple extends Resource { + @Override + default Type getValueType() { + return Type.TRIPLE; + } + @Override default boolean isTriple() { return true; diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Value.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Value.java index d54f18e762d..cf4ee2c3cb6 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Value.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Value.java @@ -17,6 +17,20 @@ */ public interface Value extends Serializable { + public enum Type { + BNODE, + IRI, + LITERAL, + TRIPLE + } + + default Type getValueType(){ + if(isIRI()) return Type.IRI; + if(isLiteral()) return Type.LITERAL; + if(isBNode()) return Type.BNODE; + return Type.TRIPLE; + } + /** * Check if the object is an instance of the given type. Typically 2x than using instanceof. *

diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractLiteral.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractLiteral.java index 635c12a8847..bcbb22aa506 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractLiteral.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractLiteral.java @@ -163,7 +163,11 @@ public TemporalAmount temporalAmountValue() throws DateTimeException { @Override public XMLGregorianCalendar calendarValue() { - return value(CalendarLiteral::parseCalendar); + XMLGregorianCalendar xmlGregorianCalendar = CalendarLiteral.parseCalendar(getLabel()); + if (xmlGregorianCalendar == null) { + throw new IllegalArgumentException("malformed value"); + } + return xmlGregorianCalendar; } @Override @@ -207,6 +211,7 @@ static class TypedLiteral extends AbstractLiteral { private final String label; private final CoreDatatype coreDatatype; private final IRI datatype; + transient private XMLGregorianCalendar cachedCalendarValue; TypedLiteral(String label) { this.label = label; @@ -260,6 +265,16 @@ public IRI getDatatype() { public CoreDatatype getCoreDatatype() { return coreDatatype; } + + @Override + public XMLGregorianCalendar calendarValue() { + XMLGregorianCalendar localCalendar = cachedCalendarValue; + if (localCalendar == null) { + localCalendar = super.calendarValue(); + cachedCalendarValue = localCalendar; + } + return localCalendar; + } } static class TaggedLiteral extends AbstractLiteral { diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/CoreDatatype.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/CoreDatatype.java index 2503ddc3bab..deb84e89294 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/CoreDatatype.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/CoreDatatype.java @@ -21,6 +21,42 @@ public interface CoreDatatype { CoreDatatype NONE = DefaultDatatype.NONE; + static int compare(CoreDatatype left, CoreDatatype right) { + if (left.getClass() == right.getClass()) { + return Integer.compare(left.ordinal(), right.ordinal()); + } + + int compare; + + if (left.isXSDDatatype()) { + if (right.isRDFDatatype() || right.isGEODatatype()) { + compare = 1; + } else { + compare = 0; + } + } else if (left.isRDFDatatype()) { + if (right.isXSDDatatype()) { + compare = -1; + } else if (right.isGEODatatype()) { + compare = 1; + } else { + compare = 0; + } + } else if (left.isGEODatatype()) { + if (right.isXSDDatatype() || right.isRDFDatatype()) { + compare = -1; + } else { + compare = 0; + } + } else { + compare = 0; + } + + return compare; + } + + int ordinal(); + /** * Checks whether the supplied datatype is an XML Schema Datatype. * @@ -42,6 +78,10 @@ default Optional asXSDDatatype() { return Optional.empty(); } + default XSD asXSDDatatypeOrNull() { + return null; + } + default Optional asRDFDatatype() { return Optional.empty(); } @@ -266,6 +306,11 @@ public String toString() { return iri.toString(); } + @Override + public final XSD asXSDDatatypeOrNull() { + return this; + } + } enum RDF implements CoreDatatype { diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleLiteral.java b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleLiteral.java index ce5ef840aa9..848c1da9b1e 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleLiteral.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleLiteral.java @@ -228,7 +228,7 @@ public IRI getDatatype() { public Optional getXsdDatatype() { CoreDatatype coreDatatype = getCoreDatatype(); - return org.eclipse.rdf4j.model.vocabulary.XSD.Datatype.from(coreDatatype.asXSDDatatype().orElse(null)); + return org.eclipse.rdf4j.model.vocabulary.XSD.Datatype.from(coreDatatype.asXSDDatatypeOrNull()); } // Overrides Object.equals(Object), implements Literal.equals(Object) diff --git a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/iterator/LeftJoinIterator.java b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/iterator/LeftJoinIterator.java index 26bedf25f09..4c038d15b05 100644 --- a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/iterator/LeftJoinIterator.java +++ b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/iterator/LeftJoinIterator.java @@ -32,6 +32,8 @@ public class LeftJoinIterator extends LookAheadIteration { + private static final EmptyIteration EMPTY_ITERATION = new EmptyIteration<>(); + /*-----------* * Variables * *-----------*/ @@ -62,7 +64,7 @@ public LeftJoinIterator(EvaluationStrategy strategy, LeftJoin join, BindingSet b leftIter = strategy.evaluate(join.getLeftArg(), bindings); // Initialize with empty iteration so that var is never null - rightIter = new EmptyIteration<>(); + rightIter = EMPTY_ITERATION; prepareRightArg = strategy.precompile(join.getRightArg(), context); join.setAlgorithm(this); @@ -82,7 +84,7 @@ public LeftJoinIterator(QueryEvaluationStep left, QueryEvaluationStep right, Que leftIter = left.evaluate(bindings); // Initialize with empty iteration so that var is never null - rightIter = new EmptyIteration<>(); + rightIter = EMPTY_ITERATION; prepareRightArg = right; this.joinCondition = joinCondition; diff --git a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/OrderComparator.java b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/OrderComparator.java index f21e472ae9f..f06caf9083d 100644 --- a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/OrderComparator.java +++ b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/OrderComparator.java @@ -43,11 +43,11 @@ public class OrderComparator implements Comparator { private final static Logger logger = LoggerFactory.getLogger(OrderComparator.class); - private final ValueComparator cmp; + private final Comparator cmp; private final Comparator bindingContentsComparator; - public OrderComparator(EvaluationStrategy strategy, Order order, ValueComparator cmp, + public OrderComparator(EvaluationStrategy strategy, Order order, Comparator cmp, QueryEvaluationContext context) { this.cmp = cmp; this.bindingContentsComparator = precompileComparator(strategy, order, context); diff --git a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/QueryEvaluationUtil.java b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/QueryEvaluationUtil.java index 21337de18ff..7b29b3efb70 100644 --- a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/QueryEvaluationUtil.java +++ b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/QueryEvaluationUtil.java @@ -65,7 +65,7 @@ public static boolean getEffectiveBooleanValue(Value value) throws ValueExprEval if (value.isLiteral()) { Literal literal = (Literal) value; String label = literal.getLabel(); - CoreDatatype.XSD datatype = literal.getCoreDatatype().asXSDDatatype().orElse(null); + CoreDatatype datatype = literal.getCoreDatatype(); if (datatype == CoreDatatype.XSD.STRING) { return label.length() > 0; @@ -79,16 +79,17 @@ public static boolean getEffectiveBooleanValue(Value value) throws ValueExprEval } catch (IllegalArgumentException e) { return false; } - } else if (datatype != null && datatype.isIntegerDatatype()) { + } else if (datatype instanceof CoreDatatype.XSD && ((CoreDatatype.XSD) datatype).isIntegerDatatype()) { try { - String normInt = XMLDatatypeUtil.normalize(label, datatype); + String normInt = XMLDatatypeUtil.normalize(label, ((CoreDatatype.XSD) datatype)); return !normInt.equals("0"); } catch (IllegalArgumentException e) { return false; } - } else if (datatype != null && datatype.isFloatingPointDatatype()) { + } else if (datatype instanceof CoreDatatype.XSD + && ((CoreDatatype.XSD) datatype).isFloatingPointDatatype()) { try { - String normFP = XMLDatatypeUtil.normalize(label, datatype); + String normFP = XMLDatatypeUtil.normalize(label, ((CoreDatatype.XSD) datatype)); return !normFP.equals("0.0E0") && !normFP.equals("NaN"); } catch (IllegalArgumentException e) { return false; @@ -162,8 +163,8 @@ public static boolean compareLiterals(Literal leftLit, Literal rightLit, Compare // - CoreDatatype.XSD:string // - RDF term (equal and unequal only) - CoreDatatype.XSD leftCoreDatatype = leftLit.getCoreDatatype().asXSDDatatype().orElse(null); - CoreDatatype.XSD rightCoreDatatype = rightLit.getCoreDatatype().asXSDDatatype().orElse(null); + CoreDatatype.XSD leftCoreDatatype = leftLit.getCoreDatatype().asXSDDatatypeOrNull(); + CoreDatatype.XSD rightCoreDatatype = rightLit.getCoreDatatype().asXSDDatatypeOrNull(); boolean leftLangLit = Literals.isLanguageLiteral(leftLit); boolean rightLangLit = Literals.isLanguageLiteral(rightLit); diff --git a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/QueryEvaluationUtility.java b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/QueryEvaluationUtility.java index fca43bbd49b..3f168ee1ad9 100644 --- a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/QueryEvaluationUtility.java +++ b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/QueryEvaluationUtility.java @@ -10,12 +10,6 @@ *******************************************************************************/ package org.eclipse.rdf4j.query.algebra.evaluation.util; -import java.util.Objects; - -import javax.xml.datatype.DatatypeConstants; -import javax.xml.datatype.Duration; -import javax.xml.datatype.XMLGregorianCalendar; - import org.eclipse.rdf4j.common.annotation.InternalUseOnly; import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.Value; @@ -24,6 +18,16 @@ import org.eclipse.rdf4j.model.util.Literals; import org.eclipse.rdf4j.query.algebra.Compare.CompareOp; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Objects; + +import static javax.xml.datatype.DatatypeConstants.FIELD_UNDEFINED; + /** * This class will take over for QueryEvaluationUtil. Currently marked as InternalUseOnly because there may still be * changes to how this class works. @@ -56,7 +60,7 @@ public static Result getEffectiveBooleanValue(Value value) { if (value.isLiteral()) { Literal literal = (Literal) value; String label = literal.getLabel(); - CoreDatatype.XSD datatype = literal.getCoreDatatype().asXSDDatatype().orElse(null); + CoreDatatype.XSD datatype = literal.getCoreDatatype().asXSDDatatypeOrNull(); if (datatype == CoreDatatype.XSD.STRING) { return Result.fromBoolean(label.length() > 0); @@ -102,12 +106,12 @@ public static Result compare(Value leftVal, Value rightVal, CompareOp operator, } else { // All other value combinations switch (operator) { - case EQ: - return Result.fromBoolean(Objects.equals(leftVal, rightVal)); - case NE: - return Result.fromBoolean(!Objects.equals(leftVal, rightVal)); - default: - return Result.incompatibleValueExpression; + case EQ: + return Result.fromBoolean(Objects.equals(leftVal, rightVal)); + case NE: + return Result.fromBoolean(!Objects.equals(leftVal, rightVal)); + default: + return Result.incompatibleValueExpression; } } } @@ -120,7 +124,7 @@ public static Result compare(Value leftVal, Value rightVal, CompareOp operator, * @param rightLit the right literal argument of the comparison. * @param operator the comparison operator to use. * @return {@code true} if execution of the supplied operator on the supplied arguments succeeds, {@code false} - * otherwise. + * otherwise. */ public static Result compareLiterals(Literal leftLit, Literal rightLit, CompareOp operator) { return compareLiterals(leftLit, rightLit, operator, true); @@ -135,46 +139,46 @@ public static Order compareLiterals(Literal leftLit, Literal rightLit, boolean s // - CoreDatatype.XSD:string // - RDF term (equal and unequal only) - CoreDatatype leftCoreDatatype = leftLit.getCoreDatatype(); - CoreDatatype rightCoreDatatype = rightLit.getCoreDatatype(); - - boolean leftLangLit = leftCoreDatatype == CoreDatatype.RDF.LANGSTRING; - boolean rightLangLit = rightCoreDatatype == CoreDatatype.RDF.LANGSTRING; - - CoreDatatype.XSD leftXSDDatatype = leftCoreDatatype.asXSDDatatype().orElse(null); - CoreDatatype.XSD rightXSDDatatype = rightCoreDatatype.asXSDDatatype().orElse(null); + CoreDatatype.XSD leftCoreDatatype = leftLit.getCoreDatatype().asXSDDatatypeOrNull(); + CoreDatatype.XSD rightCoreDatatype = rightLit.getCoreDatatype().asXSDDatatypeOrNull(); // for purposes of query evaluation in SPARQL, simple literals and string-typed literals with the same lexical // value are considered equal. if (leftCoreDatatype == CoreDatatype.XSD.STRING && rightCoreDatatype == CoreDatatype.XSD.STRING) { return Order.from(leftLit.getLabel().compareTo(rightLit.getLabel())); - } else if (!(leftLangLit || rightLangLit)) { + } else if (leftCoreDatatype != null + && rightCoreDatatype != null) { - CoreDatatype.XSD commonDatatype = getCommonDatatype(strict, leftXSDDatatype, rightXSDDatatype); + if (leftCoreDatatype.isXSDDatatype() && rightCoreDatatype.isXSDDatatype()) { - if (commonDatatype != null) { + CoreDatatype.XSD commonDatatype = getCommonDatatype(strict, leftCoreDatatype, rightCoreDatatype); - try { - Order order = handleCommonDatatype(leftLit, rightLit, strict, leftXSDDatatype, rightXSDDatatype, - leftLangLit, rightLangLit, commonDatatype); + if (commonDatatype != null) { + + try { + Order order = handleCommonDatatype(leftLit, rightLit, strict, leftCoreDatatype, + rightCoreDatatype, + commonDatatype); + + if (order == Order.illegalArgument) { + if (leftLit.equals(rightLit)) { + return Order.equal; + } + } - if (order == Order.illegalArgument) { + if (order != null) { + return order; + } + } catch (IllegalArgumentException e) { if (leftLit.equals(rightLit)) { return Order.equal; } } - if (order != null) { - return order; - } - } catch (IllegalArgumentException e) { - if (leftLit.equals(rightLit)) { - return Order.equal; - } } - } + } // All other cases, e.g. literals with languages, unequal or @@ -182,7 +186,9 @@ public static Order compareLiterals(Literal leftLit, Literal rightLit, boolean s // using the operators 'EQ' and 'NE'. See SPARQL's RDFterm-equal // operator - return otherCases(leftLit, rightLit, leftXSDDatatype, rightXSDDatatype, leftLangLit, rightLangLit); + return otherCases(leftLit, rightLit, leftCoreDatatype, + rightCoreDatatype, leftCoreDatatype == null && leftLit.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING, + rightCoreDatatype == null && rightLit.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING); } @@ -195,16 +201,144 @@ public static Order compareLiterals(Literal leftLit, Literal rightLit, boolean s * @param strict boolean indicating whether comparison should use strict (minimally-conforming) SPARQL 1.1 * operator behavior, or extended behavior. * @return {@code true} if execution of the supplied operator on the supplied arguments succeeds, {@code false} - * otherwise. + * otherwise. */ public static Result compareLiterals(Literal leftLit, Literal rightLit, CompareOp operator, boolean strict) { Order order = compareLiterals(leftLit, rightLit, strict); return order.toResult(operator); } + public static Instant xmlGregorianCalendarToInstant(XMLGregorianCalendar xmlGregCal) { + int year = xmlGregCal.getYear(); + if (year <= 1973 || year >= 2038) { + return null; + } + + int month = xmlGregCal.getMonth(); + if (month < 0) { + return null; + } + + int day = xmlGregCal.getDay(); + if (day < 0) { + return null; + } + + int hour = xmlGregCal.getHour(); + if (hour < 0) { + return null; + } + + int minute = xmlGregCal.getMinute(); + if (minute < 0) { + return null; + } + + int second = xmlGregCal.getSecond(); + if (second < 0) { + return null; + } + + int nanosecond = xmlGregCal.getFractionalSecond() != null + ? xmlGregCal.getFractionalSecond().movePointRight(9).intValue() + : 0; + if (nanosecond < 0) { + return null; + } + + LocalDateTime localDateTime = LocalDateTime.of(year, month, day, hour, minute, second, nanosecond); + ZoneOffset zoneOffset = xmlGregCal.getTimezone() == FIELD_UNDEFINED + ? ZoneOffset.UTC + : ZoneOffset.ofTotalSeconds(xmlGregCal.getTimezone() * 60); + return localDateTime.toInstant(zoneOffset); + } + + public static Instant xmlGregorianCalendarDateToInstant(XMLGregorianCalendar xmlGregCal) { + int year = xmlGregCal.getYear(); + if (year <= 1973 || year >= 2038) { + return null; + } + + int month = xmlGregCal.getMonth(); + if (month < 0) { + return null; + } + + int day = xmlGregCal.getDay(); + if (day < 0) { + return null; + } + + int timezone = xmlGregCal.getTimezone(); + if (timezone == FIELD_UNDEFINED || timezone == 0) { + return yearMonthDayToInstant(year, month, day); + } + + LocalDateTime localDateTime = LocalDateTime.of(year, month, day, 0, 0, 0, 0); + ZoneOffset zoneOffset = xmlGregCal.getTimezone() == FIELD_UNDEFINED + ? ZoneOffset.UTC + : ZoneOffset.ofTotalSeconds(xmlGregCal.getTimezone() * 60); + return localDateTime.toInstant(zoneOffset); + } + + private final static int[] daysInMonth = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + public static Instant yearMonthDayToInstant(int year, int month, int day) { + + // Calculate the number of days from 1970 to the given year + long days = (year - 1970) * 365L + (year - 1969) / 4 - (year - 1901) / 100 + (year - 1601) / 400; + + // Adjust for leap years + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) { + daysInMonth[2] = 29; + } + + // Add the number of days in each month up to the given month + for (int i = 1; i < month; i++) { + days += daysInMonth[i]; + } + + // Add the number of days in the given month + days += day - 1; + + // Calculate the number of seconds and create an Instant object + long seconds = days * 24 * 60 * 60; + return Instant.ofEpochSecond(seconds); + } + + public static long toEpoch(int year, int month, int day, int hour, int minute, int second) { + + long dateEpoch = ((long) day + (long) (year - ((14 - month) / 12)) + ((long) (year - ((14 - month) / 12))) / 4 + - ((long) (year - ((14 - month) / 12))) / 100 + ((long) (year - ((14 - month) / 12))) / 400 + + (31 * ((long) (month + (12 * ((14 - month) / 12) - 2)))) / 12) - 719529; + +// +// // Calculate the number of days from 1970 to the given year +// long days = (year - 1970) * 365L + (year - 1969) / 4 - (year - 1901) / 100 + (year - 1601) / 400; +// +// // Adjust for leap years +// if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) { +// daysInMonth[2] = 29; +// } +// +// // Add the number of days in each month up to the given month +// for (int i = 1; i < month; i++) { +// days += daysInMonth[i]; +// } +// +// // Add the number of days in the given month +// days += day - 1; +// +// // Calculate the number of seconds +// long dateEpoch = days * 24 * 60 * 60; + + return dateEpoch + hour * 3600L + minute * 60L + second; + + } + private static Order handleCommonDatatype(Literal leftLit, Literal rightLit, boolean strict, - CoreDatatype.XSD leftCoreDatatype, CoreDatatype.XSD rightCoreDatatype, boolean leftLangLit, - boolean rightLangLit, CoreDatatype.XSD commonDatatype) { + CoreDatatype.XSD leftCoreDatatype, CoreDatatype.XSD rightCoreDatatype, + CoreDatatype.XSD commonDatatype) { if (commonDatatype == CoreDatatype.XSD.DOUBLE) { return Order.from(Double.compare(leftLit.doubleValue(), rightLit.doubleValue())); } else if (commonDatatype == CoreDatatype.XSD.FLOAT) { @@ -216,10 +350,27 @@ private static Order handleCommonDatatype(Literal leftLit, Literal rightLit, boo } else if (commonDatatype == CoreDatatype.XSD.BOOLEAN) { return Order.from(Boolean.compare(leftLit.booleanValue(), rightLit.booleanValue())); } else if (commonDatatype.isCalendarDatatype()) { + +// if (commonDatatype == CoreDatatype.XSD.DATETIME) { +// Instant leftInstant = xmlGregorianCalendarToInstant(leftLit.calendarValue()); +// Instant rightInstant = xmlGregorianCalendarToInstant(rightLit.calendarValue()); +// +// if (leftInstant != null && rightInstant != null) { +// return Order.from(leftInstant.compareTo(rightInstant)); +// } +// } else if (commonDatatype == CoreDatatype.XSD.DATE) { +// Instant leftInstant = xmlGregorianCalendarDateToInstant(leftLit.calendarValue()); +// Instant rightInstant = xmlGregorianCalendarDateToInstant(rightLit.calendarValue()); +// +// if (leftInstant != null && rightInstant != null) { +// return Order.from(leftInstant.compareTo(rightInstant)); +// } +// } + XMLGregorianCalendar left = leftLit.calendarValue(); XMLGregorianCalendar right = rightLit.calendarValue(); - int compare = left.compare(right); + int compare = compareXMLGregorianCalendar(leftCoreDatatype, rightCoreDatatype, left, right, leftLit, rightLit); // Note: XMLGregorianCalendar.compare() returns compatible values (-1, 0, 1) but INDETERMINATE // needs special treatment @@ -240,7 +391,7 @@ private static Order handleCommonDatatype(Literal leftLit, Literal rightLit, boo if (compare != DatatypeConstants.INDETERMINATE) { return Order.from(compare); } else { - return otherCases(leftLit, rightLit, leftCoreDatatype, rightCoreDatatype, leftLangLit, rightLangLit); + return otherCases(leftLit, rightLit, leftCoreDatatype, rightCoreDatatype, false, false); } } else if (commonDatatype == CoreDatatype.XSD.STRING) { @@ -250,13 +401,49 @@ private static Order handleCommonDatatype(Literal leftLit, Literal rightLit, boo return null; } - private static Order otherCases(Literal leftLit, Literal rightLit, CoreDatatype.XSD leftCoreDatatype, - CoreDatatype.XSD rightCoreDatatype, boolean leftLangLit, boolean rightLangLit) { + private static int compareXMLGregorianCalendar(CoreDatatype.XSD leftCoreDatatype, + CoreDatatype.XSD rightCoreDatatype, XMLGregorianCalendar left, XMLGregorianCalendar right, Literal leftLit, Literal rightLit) { + if (leftCoreDatatype == rightCoreDatatype && left.getTimezone() == right.getTimezone()) { + int leftYear = left.getYear(); + int rightYear = right.getYear(); + if (leftYear > 1971 && rightYear > 1971 && leftYear < 2038 && rightYear < 2038) { + + int compare = Long.compare( + toEpoch(leftYear, left.getMonth(), left.getDay(), left.getHour(), left.getMinute(), + left.getSecond()), + toEpoch(rightYear, right.getMonth(), right.getDay(), right.getHour(), right.getMinute(), + right.getSecond()) + ); + if (compare != 0) { + // since the values are different we can assume that we don't need to account for a higher precision + return compare; + } else { + // since the values are equal we need to account for a higher precision + if (leftLit.getLabel().equals(rightLit.getLabel())) { + return 0; + } else { + return left.compare(right); + } + } + } else { + // since the values are equal we need to account for a higher precision + if (leftLit.getLabel().equals(rightLit.getLabel())) { + return 0; + } else { + return left.compare(right); + } } + } else { + return left.compare(right); + } + } + + private static Order otherCases(Literal leftLit, Literal rightLit, CoreDatatype leftCoreDatatype, + CoreDatatype rightCoreDatatype, boolean leftLangLit, boolean rightLangLit) { boolean literalsEqual = leftLit.equals(rightLit); if (!literalsEqual) { if (!leftLangLit && !rightLangLit && isSupportedDatatype(leftCoreDatatype) - && isSupportedDatatype(rightCoreDatatype)) { + && isSupportedDatatype(rightCoreDatatype)) { // left and right arguments have incompatible but supported datatypes // we need to check that the lexical-to-value mapping for both datatypes succeeds @@ -269,19 +456,22 @@ && isSupportedDatatype(rightCoreDatatype)) { } boolean leftString = leftCoreDatatype == CoreDatatype.XSD.STRING; - boolean leftNumeric = leftCoreDatatype.isNumericDatatype(); - boolean leftDate = leftCoreDatatype.isCalendarDatatype(); - boolean rightString = rightCoreDatatype == CoreDatatype.XSD.STRING; - boolean rightNumeric = rightCoreDatatype.isNumericDatatype(); - boolean rightDate = rightCoreDatatype.isCalendarDatatype(); if (leftString != rightString) { return Order.incompatibleValueExpression; } + + boolean leftNumeric = ((CoreDatatype.XSD) leftCoreDatatype).isNumericDatatype(); + boolean rightNumeric = ((CoreDatatype.XSD) rightCoreDatatype).isNumericDatatype(); + if (leftNumeric != rightNumeric) { return Order.incompatibleValueExpression; } + + boolean leftDate = ((CoreDatatype.XSD) leftCoreDatatype).isCalendarDatatype(); + boolean rightDate = ((CoreDatatype.XSD) rightCoreDatatype).isCalendarDatatype(); + if (leftDate != rightDate) { return Order.incompatibleValueExpression; } @@ -298,38 +488,50 @@ && isSupportedDatatype(rightCoreDatatype)) { } private static CoreDatatype.XSD getCommonDatatype(boolean strict, CoreDatatype.XSD leftCoreDatatype, - CoreDatatype.XSD rightCoreDatatype) { - if (leftCoreDatatype != null && rightCoreDatatype != null) { - if (leftCoreDatatype == rightCoreDatatype) { - return leftCoreDatatype; - } else if (leftCoreDatatype.isNumericDatatype() && rightCoreDatatype.isNumericDatatype()) { - // left and right arguments have different datatypes, try to find a more general, shared datatype - if (leftCoreDatatype == CoreDatatype.XSD.DOUBLE || rightCoreDatatype == CoreDatatype.XSD.DOUBLE) { - return CoreDatatype.XSD.DOUBLE; - } else if (leftCoreDatatype == CoreDatatype.XSD.FLOAT || rightCoreDatatype == CoreDatatype.XSD.FLOAT) { - return CoreDatatype.XSD.FLOAT; - } else if (leftCoreDatatype == CoreDatatype.XSD.DECIMAL - || rightCoreDatatype == CoreDatatype.XSD.DECIMAL) { - return CoreDatatype.XSD.DECIMAL; - } else { - return CoreDatatype.XSD.INTEGER; - } - } else if (!strict && leftCoreDatatype.isCalendarDatatype() && rightCoreDatatype.isCalendarDatatype()) { - // We're not running in strict eval mode so we use extended datatype comparsion. + CoreDatatype.XSD rightCoreDatatype) { + if (leftCoreDatatype == null || rightCoreDatatype == null) { + return null; + } + + if (leftCoreDatatype == rightCoreDatatype) { + return leftCoreDatatype; + } + + if (leftCoreDatatype.isNumericDatatype() && rightCoreDatatype.isNumericDatatype()) { + return getCommonNumericDatatype(leftCoreDatatype, rightCoreDatatype); + } + + if (!strict) { + if (leftCoreDatatype.isCalendarDatatype() && rightCoreDatatype.isCalendarDatatype()) { return CoreDatatype.XSD.DATETIME; - } else if (!strict && leftCoreDatatype.isDurationDatatype() && rightCoreDatatype.isDurationDatatype()) { + } else if (leftCoreDatatype.isDurationDatatype() && rightCoreDatatype.isDurationDatatype()) { return CoreDatatype.XSD.DURATION; } } + return null; } + private static CoreDatatype.XSD getCommonNumericDatatype(CoreDatatype.XSD leftCoreDatatype, + CoreDatatype.XSD rightCoreDatatype) { + if (leftCoreDatatype == CoreDatatype.XSD.DOUBLE || rightCoreDatatype == CoreDatatype.XSD.DOUBLE) { + return CoreDatatype.XSD.DOUBLE; + } + if (leftCoreDatatype == CoreDatatype.XSD.FLOAT || rightCoreDatatype == CoreDatatype.XSD.FLOAT) { + return CoreDatatype.XSD.FLOAT; + } + if (leftCoreDatatype == CoreDatatype.XSD.DECIMAL || rightCoreDatatype == CoreDatatype.XSD.DECIMAL) { + return CoreDatatype.XSD.DECIMAL; + } + return CoreDatatype.XSD.INTEGER; + } + /** * Checks whether the supplied value is a "plain literal". A "plain literal" is a literal with no datatype and * optionally a language tag. * * @see RDF Literal - * Documentation + * Documentation */ public static boolean isPlainLiteral(Value v) { if (v.isLiteral()) { @@ -339,8 +541,8 @@ public static boolean isPlainLiteral(Value v) { } public static boolean isPlainLiteral(Literal l) { - assert l.getLanguage().isEmpty() || (l.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING); - return l.getCoreDatatype() == CoreDatatype.XSD.STRING || l.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING; + CoreDatatype coreDatatype = l.getCoreDatatype(); + return coreDatatype == CoreDatatype.XSD.STRING || coreDatatype == CoreDatatype.RDF.LANGSTRING; } /** @@ -403,7 +605,7 @@ public static boolean isStringLiteral(Value v) { * @param arg2 the second argument * @return true iff the two supplied arguments are argument compatible, false otherwise * @see SPARQL Argument Compatibility - * Rules + * Rules */ public static boolean compatibleArguments(Literal arg1, Literal arg2) { // 1. The arguments are literals typed as CoreDatatype.XSD:string @@ -412,9 +614,9 @@ public static boolean compatibleArguments(Literal arg1, Literal arg2) { // argument is a literal typed as CoreDatatype.XSD:string return (isSimpleLiteral(arg1) && isSimpleLiteral(arg2)) - || (Literals.isLanguageLiteral(arg1) && Literals.isLanguageLiteral(arg2) - && arg1.getLanguage().equals(arg2.getLanguage())) - || (Literals.isLanguageLiteral(arg1) && isSimpleLiteral(arg2)); + || (Literals.isLanguageLiteral(arg1) && Literals.isLanguageLiteral(arg2) + && arg1.getLanguage().equals(arg2.getLanguage())) + || (Literals.isLanguageLiteral(arg1) && isSimpleLiteral(arg2)); } /** @@ -427,9 +629,10 @@ public static boolean isStringLiteral(Literal l) { return l.getCoreDatatype() == CoreDatatype.XSD.STRING || l.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING; } - private static boolean isSupportedDatatype(CoreDatatype.XSD datatype) { - return datatype != null && (datatype == CoreDatatype.XSD.STRING || datatype.isNumericDatatype() - || datatype.isCalendarDatatype()); + private static boolean isSupportedDatatype(CoreDatatype datatype) { + return datatype != null && datatype.isXSDDatatype() + && (datatype == CoreDatatype.XSD.STRING || ((CoreDatatype.XSD) datatype).isNumericDatatype() + || ((CoreDatatype.XSD) datatype).isCalendarDatatype()); } public enum Result { @@ -515,35 +718,35 @@ public Result toResult(CompareOp operator) { if (this == notEqual) { switch (operator) { - case EQ: - return Result._false; - case NE: - return Result._true; + case EQ: + return Result._false; + case NE: + return Result._true; + case LT: + case LE: + case GE: + case GT: + return Result.incompatibleValueExpression; + default: + return Result.illegalArgument; + } + } + + switch (operator) { case LT: + return Result.fromBoolean(value < 0); case LE: + return Result.fromBoolean(value <= 0); + case EQ: + return Result.fromBoolean(value == 0); + case NE: + return Result.fromBoolean(value != 0); case GE: + return Result.fromBoolean(value >= 0); case GT: - return Result.incompatibleValueExpression; + return Result.fromBoolean(value > 0); default: return Result.illegalArgument; - } - } - - switch (operator) { - case LT: - return Result.fromBoolean(value < 0); - case LE: - return Result.fromBoolean(value <= 0); - case EQ: - return Result.fromBoolean(value == 0); - case NE: - return Result.fromBoolean(value != 0); - case GE: - return Result.fromBoolean(value >= 0); - case GT: - return Result.fromBoolean(value > 0); - default: - return Result.illegalArgument; } } } diff --git a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/ValueComparator.java b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/ValueComparator.java index c01a7f9e8f6..469c709e098 100644 --- a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/ValueComparator.java +++ b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/ValueComparator.java @@ -11,7 +11,6 @@ package org.eclipse.rdf4j.query.algebra.evaluation.util; import java.util.Comparator; -import java.util.Optional; import org.eclipse.rdf4j.model.BNode; import org.eclipse.rdf4j.model.IRI; @@ -46,47 +45,42 @@ public int compare(Value o1, Value o2) { return 1; } - // 2. Blank nodes - boolean b1 = o1.isBNode(); - boolean b2 = o2.isBNode(); - if (b1 && b2) { - return compareBNodes((BNode) o1, (BNode) o2); - } - if (b1) { - return -1; - } - if (b2) { - return 1; + if(o1.getClass() == o2.getClass()){ + return compareSameTypes(o1, o2, o1.getValueType()); } - // 3. IRIs - boolean iri1 = o1.isIRI(); - boolean iri2 = o2.isIRI(); - if (iri1 && iri2) { - return compareURIs((IRI) o1, (IRI) o2); - } - if (iri1) { - return -1; - } - if (iri2) { - return 1; + Value.Type o1Type = o1.getValueType(); + Value.Type o2Type = o2.getValueType(); + + if (o1Type == o2Type) { + return compareSameTypes(o1, o2, o1Type); } - // 4. Literals - boolean l1 = o1.isLiteral(); - boolean l2 = o2.isLiteral(); - if (l1 && l2) { + return compareDifferentTypes(o1Type, o2Type); + } + + private int compareSameTypes(Value o1, Value o2, Value.Type type) { + switch (type) { + case BNODE: + return compareBNodes((BNode) o1, (BNode) o2); + case IRI: + return compareIRIs((IRI) o1, (IRI) o2); + case LITERAL: return compareLiterals((Literal) o1, (Literal) o2); + default: + return compareTriples((Triple) o1, (Triple) o2); } - if (l1) { - return -1; - } - if (l2) { - return 1; - } + } - // 5. RDF-star triples - return compareTriples((Triple) o1, (Triple) o2); + private static int compareDifferentTypes(Value.Type o1Type, Value.Type o2Type) { + /* + * Using ordinal is an optimization written by ChatGPT 4 instead of the following code: + * + * if (o1Type == Value.Type.BNODE) { return -1; } if (o2Type == Value.Type.BNODE) { return 1; } if (o1Type == + * Value.Type.IRI) { return -1; } if (o2Type == Value.Type.IRI) { return 1; } if (o1Type == Value.Type.LITERAL) + * { return -1; } return 1; + */ + return o1Type.ordinal() < o2Type.ordinal() ? -1 : 1; } public void setStrict(boolean flag) { @@ -101,8 +95,8 @@ private int compareBNodes(BNode leftBNode, BNode rightBNode) { return leftBNode.getID().compareTo(rightBNode.getID()); } - private int compareURIs(IRI leftURI, IRI rightURI) { - return leftURI.toString().compareTo(rightURI.toString()); + private int compareIRIs(IRI leftURI, IRI rightURI) { + return leftURI.stringValue().compareTo(rightURI.stringValue()); } private int compareLiterals(Literal leftLit, Literal rightLit) { @@ -135,84 +129,70 @@ private QueryEvaluationUtility.Order compareNonPlainLiterals(Literal leftLit, Li } private int comparePlainLiterals(Literal leftLit, Literal rightLit) { - int result; - - // FIXME: Confirm these rules work with RDF-1.1 - // Sort by datatype first, plain literals come before datatyped literals IRI leftDatatype = leftLit.getDatatype(); IRI rightDatatype = rightLit.getDatatype(); - if (leftDatatype != null) { - if (rightDatatype != null) { + if (leftDatatype != rightDatatype) { + if (leftDatatype != null && rightDatatype != null) { // Both literals have datatypes - CoreDatatype.XSD leftXmlDatatype = leftLit.getCoreDatatype().asXSDDatatype().orElse(null); - CoreDatatype.XSD rightXmlDatatype = rightLit.getCoreDatatype().asXSDDatatype().orElse(null); - - result = compareDatatypes(leftXmlDatatype, rightXmlDatatype, leftDatatype, rightDatatype); + int result = compareDatatypes(leftLit.getCoreDatatype(), rightLit.getCoreDatatype(), leftDatatype, + rightDatatype); if (result != 0) { return result; } - } else { - return 1; + return leftDatatype == null ? -1 : 1; } - } else if (rightDatatype != null) { - return -1; } - // datatypes are equal or both literals are untyped; sort by language - // tags, simple literals come before literals with language tags - Optional leftLanguage = leftLit.getLanguage(); - Optional rightLanguage = rightLit.getLanguage(); + boolean leftIsLang = leftLit.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING; + boolean rightIsLang = rightLit.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING; - if (leftLanguage.isPresent()) { - if (rightLanguage.isPresent()) { - result = leftLanguage.get().compareTo(rightLanguage.get()); - if (result != 0) { - return result; - } - } else { - return 1; + if (leftIsLang && rightIsLang) { + int result = leftLit.getLanguage().get().compareTo(rightLit.getLanguage().get()); + if (result != 0) { + return result; } - } else if (rightLanguage.isPresent()) { - return -1; + } else if (leftIsLang || rightIsLang) { + return leftIsLang ? 1 : -1; } - // Literals are equal as fas as their datatypes and language tags are - // concerned, compare their labels + // Literals are equal as far as their datatypes and language tags are concerned, compare their labels return leftLit.getLabel().compareTo(rightLit.getLabel()); } - private int compareDatatypes(CoreDatatype.XSD leftDatatype, CoreDatatype.XSD rightDatatype, IRI leftDatatypeIRI, + private int compareDatatypes(CoreDatatype leftCoreDatatype, CoreDatatype rightCoreDatatype, IRI leftDatatypeIRI, IRI rightDatatypeIRI) { - if (leftDatatype != null && leftDatatype == rightDatatype) { + + if (leftCoreDatatype == CoreDatatype.NONE || rightCoreDatatype == CoreDatatype.NONE) { + return compareIRIs(leftDatatypeIRI, rightDatatypeIRI); + } + + if (leftCoreDatatype == rightCoreDatatype) { return 0; - } else if (leftDatatype != null && leftDatatype.isNumericDatatype()) { - if (rightDatatype != null && rightDatatype.isNumericDatatype()) { - // both are numeric datatypes - return leftDatatype.compareTo(rightDatatype); - } else { - return -1; - } - } else if (rightDatatype != null && rightDatatype.isNumericDatatype()) { - return 1; - } else if (leftDatatype != null && leftDatatype.isCalendarDatatype()) { - if (rightDatatype != null && rightDatatype.isCalendarDatatype()) { - return leftDatatype.compareTo(rightDatatype); - } else { - return -1; - } - } else if (rightDatatype != null && rightDatatype.isCalendarDatatype()) { - return 1; } - if (leftDatatype != null && rightDatatype != null) { - return leftDatatype.compareTo(rightDatatype); + CoreDatatype.XSD leftXsdDatatype = leftCoreDatatype.asXSDDatatypeOrNull(); + CoreDatatype.XSD rightXsdDatatype = rightCoreDatatype.asXSDDatatypeOrNull(); + + boolean leftNumeric = leftXsdDatatype != null && leftXsdDatatype.isNumericDatatype(); + boolean rightNumeric = rightXsdDatatype != null && rightXsdDatatype.isNumericDatatype(); + boolean leftCalendar = leftXsdDatatype != null && leftXsdDatatype.isCalendarDatatype(); + boolean rightCalendar = rightXsdDatatype != null && rightXsdDatatype.isCalendarDatatype(); + + if (leftNumeric && rightNumeric || leftCalendar && rightCalendar) { + return CoreDatatype.compare(leftCoreDatatype, rightCoreDatatype); + } + + if (leftNumeric || leftCalendar) { + return -1; } - // incompatible or unordered datatype - return compareURIs(leftDatatypeIRI, rightDatatypeIRI); + if (rightNumeric || rightCalendar) { + return 1; + } + return CoreDatatype.compare(leftCoreDatatype, rightCoreDatatype); } private int compareTriples(Triple leftTriple, Triple rightTriple) { diff --git a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/XMLDatatypeMathUtil.java b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/XMLDatatypeMathUtil.java index 090ec7c5b05..9ad025c8820 100644 --- a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/XMLDatatypeMathUtil.java +++ b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/util/XMLDatatypeMathUtil.java @@ -38,8 +38,8 @@ public class XMLDatatypeMathUtil { * @return a datatype literal */ public static Literal compute(Literal leftLit, Literal rightLit, MathOp op) throws ValueExprEvaluationException { - CoreDatatype.XSD leftDatatype = leftLit.getCoreDatatype().asXSDDatatype().orElse(null); - CoreDatatype.XSD rightDatatype = rightLit.getCoreDatatype().asXSDDatatype().orElse(null); + CoreDatatype.XSD leftDatatype = leftLit.getCoreDatatype().asXSDDatatypeOrNull(); + CoreDatatype.XSD rightDatatype = rightLit.getCoreDatatype().asXSDDatatypeOrNull(); if (leftDatatype != null && rightDatatype != null) { if (leftDatatype.isNumericDatatype() && rightDatatype.isNumericDatatype()) { diff --git a/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/util/OrderComparatorTest.java b/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/util/OrderComparatorTest.java index 53b1999234e..3713281367e 100644 --- a/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/util/OrderComparatorTest.java +++ b/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/util/OrderComparatorTest.java @@ -14,6 +14,7 @@ import java.time.Instant; import java.util.Arrays; +import java.util.Comparator; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -109,7 +110,7 @@ public void setQueryEvaluationMode(QueryEvaluationMode queryEvaluationMode) { } } - class ComparatorStub extends ValueComparator { + class ComparatorStub implements Comparator { Iterator iter; diff --git a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/benchmark/SortBenchmark.java b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/benchmark/SortBenchmark.java index 8b932a0418a..25163ccd867 100644 --- a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/benchmark/SortBenchmark.java +++ b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/benchmark/SortBenchmark.java @@ -43,10 +43,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; -import org.openjdk.jmh.runner.options.Options; -import org.openjdk.jmh.runner.options.OptionsBuilder; /** * @author HÃ¥vard Ottestad @@ -77,12 +74,21 @@ public class SortBenchmark { List valuesList; public static void main(String[] args) throws RunnerException, IOException, InterruptedException { - Options opt = new OptionsBuilder() - .include("SortBenchmark.*") // adapt to run other benchmark tests - .forks(1) - .build(); - - new Runner(opt).run(); +// Options opt = new OptionsBuilder() +// .include("SortBenchmark.*") // adapt to run other benchmark tests +// .forks(1) +// .build(); +// +// new Runner(opt).run(); + + long temp = 0; + SortBenchmark sortBenchmark = new SortBenchmark(); + sortBenchmark.setup(); + for (int i = 0; i < 2; i++) { + System.out.println("i = " + i); + temp += sortBenchmark.compareAllDirectlySingleThreaded(); + } + System.out.println("temp = " + temp); } @Setup(Level.Trial) @@ -157,4 +163,33 @@ public Value sortDirectly() { } + @Benchmark + public Value sortDirectlySingleThreaded() { + + Value[] values = new ArrayList<>(valuesList).toArray(new Value[0]); + + Arrays.sort(values, new ValueComparator()); + + return values[0]; + + } + + @Benchmark + public long compareAllDirectlySingleThreaded() { + + ValueComparator valueComparator = new ValueComparator(); + long compare = 0; + + + for (Value value1 : valuesList) { + for (Value value2 : valuesList) { + compare += valueComparator.compare(value1, value2); + + } + } + + return compare; + + } + } diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/DatatypeFilter.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/DatatypeFilter.java index 003a496493c..5d1eec7943e 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/DatatypeFilter.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/DatatypeFilter.java @@ -30,7 +30,7 @@ public class DatatypeFilter extends FilterPlanNode { public DatatypeFilter(PlanNode parent, IRI datatype) { super(parent); this.datatype = datatype; - this.xsdDatatype = CoreDatatype.from(datatype).asXSDDatatype().orElse(null); + this.xsdDatatype = CoreDatatype.from(datatype).asXSDDatatypeOrNull(); // stackTrace = Thread.currentThread().getStackTrace(); }