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();
}