This is an automated email from the ASF dual-hosted git repository.
afs pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 719d2669ed GH-4181: Validate ExprTripleTerm for triple term rules
719d2669ed is described below
commit 719d2669ed23c823fb87f05c7e6193eded735ef1
Author: Andy Seaborne <[email protected]>
AuthorDate: Tue Sep 1 16:49:41 2026 +0100
GH-4181: Validate ExprTripleTerm for triple term rules
---
.../apache/jena/sparql/expr/ExprTripleTerm.java | 9 ++++++
.../function/library/triple/TripleTermOps.java | 6 ++--
.../java/org/apache/jena/sparql/expr/TS_Expr.java | 2 +-
...Terms.java => TestExprTripleTermFunctions.java} | 32 +++++++++++++++++-----
.../apache/jena/sparql/expr/TestExpressions.java | 9 +++---
.../jena/sparql/expr/TestNodeFunctionsMisc.java | 4 +--
jena-arq/testing/ARQ/Extra/expr-triple-term.rq | 7 +++++
jena-arq/testing/ARQ/Extra/expr-triple-term.srj | 24 ++++++++++++++++
jena-arq/testing/ARQ/Extra/expr-triple-term.ttl | 4 +++
jena-arq/testing/ARQ/Extra/manifest.ttl | 7 +++++
10 files changed, 86 insertions(+), 18 deletions(-)
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/expr/ExprTripleTerm.java
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/ExprTripleTerm.java
index c03b7f844c..a5b48c71cb 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/ExprTripleTerm.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/ExprTripleTerm.java
@@ -60,6 +60,15 @@ public class ExprTripleTerm extends ExprNode {
Triple t1 = tripleTerm.getTriple();
Triple t2 = Substitute.substitute(t1, binding);
if ( t2.isConcrete() ) {
+ Node s = t2.getSubject();
+ Node p = t2.getPredicate();
+ // Check it.
+ if ( s.isTripleTerm() )
+ throw new ExprEvalException("triple term: Subject is a triple
term: "+s);
+ if ( !s.isURI() && !s.isBlank() )
+ throw new ExprEvalException("triple term: Subject is not a URI
or blank node: "+s);
+ if ( !p.isURI() )
+ throw new ExprEvalException("triple term: Predicate is not a
URI: "+p);
Node tripleTerm2 = NodeFactory.createTripleTerm(t2);
return NodeValue.makeNode(tripleTerm2);
}
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/triple/TripleTermOps.java
b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/triple/TripleTermOps.java
index fa7611a682..c4db950566 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/triple/TripleTermOps.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/triple/TripleTermOps.java
@@ -26,7 +26,6 @@ import java.util.function.Function;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Triple;
-import org.apache.jena.query.ARQ;
import org.apache.jena.sparql.expr.ExprEvalException;
import org.apache.jena.sparql.expr.NodeValue;
@@ -38,11 +37,12 @@ public class TripleTermOps {
*/
public static NodeValue fnTriple(NodeValue nv1, NodeValue nv2, NodeValue
nv3) {
Node s = nv1.asNode();
- if ( ARQ.isStrictMode() ) {
+ //if ( ARQ.isStrictMode() ) {
+ if ( true ) {
if ( s.isTripleTerm() )
throw new ExprEvalException("triple: Subject is a triple term:
"+nv1);
if ( !s.isURI() && !s.isBlank() )
- throw new ExprEvalException("triple: Subject is not a URI or
blank node: "+nv2);
+ throw new ExprEvalException("triple: Subject is not a URI or
blank node: "+nv1);
}
Node p = nv2.asNode();
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TS_Expr.java
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TS_Expr.java
index f35dff4e51..2092860076 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TS_Expr.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TS_Expr.java
@@ -44,7 +44,7 @@ import
org.apache.jena.sparql.expr.nodevalue.TestNodeValueSortKey;
, TestStringArgCompatibility.class
, TestSPARQLKeywordFunctions.class
, TestFunctionsByURI.class
- , TestExprTripleTerms.class
+ , TestExprTripleTermFunctions.class
, TestLeviathanFunctions.class
, TestNodeValueOps.class
, TestOrdering.class
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExprTripleTerms.java
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExprTripleTermFunctions.java
similarity index 74%
rename from
jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExprTripleTerms.java
rename to
jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExprTripleTermFunctions.java
index 89da1e841b..d6dcc8a984 100644
---
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExprTripleTerms.java
+++
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExprTripleTermFunctions.java
@@ -38,7 +38,10 @@ import org.apache.jena.sys.JenaSystem;
/**
* Tests for TRIPLE, SUBJECT, PREDICATE, OBJECT, isTRIPLE
*/
-public class TestExprTripleTerms {
+public class TestExprTripleTermFunctions {
+
+ // "(triple s p o)" is the function call TRIPLE(s,p,o)
+ // "(tripleterm s p o)" is syntax <<( s p o )>>
static { JenaSystem.init(); }
@@ -48,35 +51,50 @@ public class TestExprTripleTerms {
}
@Test
- public void tripleTerm_Bad1() {
+ public void tripleFunction_Bad1() {
assertThrows(ExprEvalException.class, ()-> eval("triple(:s1, 'bc',
:o1)") );
}
@Test
- public void tripleTerm_Access1() {
+ public void tripleFunction_Access1() {
test("subject(triple(:s1, :p1, :o1))", ":s1");
}
@Test
- public void tripleTerm_Access2() {
+ public void tripleFunction_Access2() {
test("predicate(triple(:s1, :p1, :o1))", ":p1");
}
@Test
- public void tripleTerm_Access3() {
+ public void tripleFunction_Access3() {
test("object(triple(:s1, :p1, :o1))", ":o1");
}
@Test
- public void tripleTerm_Test1() {
+ public void tripleFunction_Test1() {
test("isTriple(triple(:s1, :p1, :o1))", "true");
}
@Test
- public void tripleTerm_Test2() {
+ public void tripleFunction_Test2() {
test("isTriple(:x)", "false");
}
+ @Test
+ public void tripleTerm_BadSubjectLiteral() {
+ assertThrows(ExprEvalException.class, ()-> eval("triple('abc', :p1,
:o1)") );
+ }
+
+ @Test
+ public void tripleTerm_BadSubjectTripleTerm() {
+ assertThrows(ExprEvalException.class, ()-> eval("triple(triple(:s1,
:p1, :o1), :p2, :o2)") );
+ }
+
+ @Test
+ public void tripleTerm_NotConcrete() {
+ assertThrows(ExprEvalException.class, ()-> eval("triple(:s, :p1,
?var)") );
+ }
+
private static Node eval(String string) {
Expr expr = ExprUtils.parse(string, pmap);
NodeValue nv = expr.eval(null, new FunctionEnvBase());
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressions.java
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressions.java
index 5716836fb4..f8d5bb8ee9 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressions.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressions.java
@@ -404,12 +404,12 @@ public class TestExpressions
@Test public void tripleterm_02() { testEval("TRIPLE(BNODE(), <x:p>,
123)"); }
@Test public void tripleterm_03() { testEval("TRIPLE(<x:s>, <x:p>,
TRIPLE(<x:s1>, <x:p1>, <x:o1>))"); }
- // Not symmetric RDF
+ // Not (symmetric) RDF
@Test public void tripleterm_10() { assertThrows(ExprEvalException.class,
()->testEval("TRIPLE(<x:s>, BNODE(), <x:o>)")); }
- // TRIPLE generates symmetric RDF (non-strict)
- @Test public void tripleterm_20() { testEval("TRIPLE(123, <x:p>, <x:o>)");
}
- @Test public void tripleterm_21() { testEval("TRIPLE(TRIPLE(<x:s>, <x:p>,
<x:o>), <x:p>, <x:o>)"); }
+ // If TRIPLE generates only legal RDF (not symmetric) on normal mode.
+ @Test public void tripleterm_20() { assertThrows(ExprEvalException.class,
()-> testEval("TRIPLE(123, <x:p>, <x:o>)")); }
+ @Test public void tripleterm_21() { assertThrows(ExprEvalException.class,
()-> testEval("TRIPLE(TRIPLE(<x:s>, <x:p>, <x:o>), <x:p>, <x:o>)")); }
// TRIPLE generates RDF triples (strict)
@Test public void tripleterm_30() {
@@ -435,7 +435,6 @@ public class TestExpressions
assertThrows(QueryParseException.class, ()-> testURI("PROPERTY(
TRIPLE(<x:s>, <x:p>, 123) )", "x:p") );
}
-
@Test public void boolean_129() { testBoolean("isURI(?x)", true, env); }
@Test public void boolean_130() { testBoolean("isURI(?a)", false, env); }
@Test public void boolean_131() { testBoolean("isURI(?b)", false, env); }
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctionsMisc.java
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctionsMisc.java
index 80465d7a88..ac803d2947 100644
---
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctionsMisc.java
+++
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctionsMisc.java
@@ -69,13 +69,13 @@ public class TestNodeFunctionsMisc {
@Test public void testRDFtermEquals5() {
Node n1 = SSE.parseNode("<<(:s :p 123)>>");
Node n2 = SSE.parseNode("<<(:s :p 123)>>");
- assertTrue(NodeFunctions.rdfTermEqual11_legacy(n1, n2));
+ assertTrue(n1.sameTermAs(n2));
}
@Test public void testRDFtermEquals6() {
Node n1 = SSE.parseNode("<<(:s :p1 123)>>");
Node n2 = SSE.parseNode("<<(:s :p2 123)>>");
- assertFalse(NodeFunctions.rdfTermEqual11_legacy(n1, n2));
+ assertFalse(n1.sameTermAs(n2));
}
@Test public void testRDFtermEquals7() {
diff --git a/jena-arq/testing/ARQ/Extra/expr-triple-term.rq
b/jena-arq/testing/ARQ/Extra/expr-triple-term.rq
new file mode 100644
index 0000000000..368932b467
--- /dev/null
+++ b/jena-arq/testing/ARQ/Extra/expr-triple-term.rq
@@ -0,0 +1,7 @@
+PREFIX : <http://example/>
+
+SELECT * WHERE {
+ ?s :p ?o .
+ BIND( <<( ?o :q :z )>> AS ?tt )
+}
+
diff --git a/jena-arq/testing/ARQ/Extra/expr-triple-term.srj
b/jena-arq/testing/ARQ/Extra/expr-triple-term.srj
new file mode 100644
index 0000000000..ae1b656fa2
--- /dev/null
+++ b/jena-arq/testing/ARQ/Extra/expr-triple-term.srj
@@ -0,0 +1,24 @@
+{ "head": {
+ "vars": [ "s" , "o" , "tt" ]
+ } ,
+ "results": {
+ "bindings": [
+ {
+ "s": { "type": "uri" , "value": "http://example/s2" } ,
+ "o": { "type": "uri" , "value": "http://example/s2" } ,
+ "tt": {
+ "type": "triple" ,
+ "value": {
+ "subject": { "type": "uri" , "value": "http://example/s2" } ,
+ "predicate": { "type": "uri" , "value": "http://example/q" } ,
+ "object": { "type": "uri" , "value": "http://example/z" }
+ }
+ }
+ } ,
+ {
+ "s": { "type": "uri" , "value": "http://example/s1" } ,
+ "o": { "type": "literal" , "value": "s1" }
+ }
+ ]
+ }
+}
diff --git a/jena-arq/testing/ARQ/Extra/expr-triple-term.ttl
b/jena-arq/testing/ARQ/Extra/expr-triple-term.ttl
new file mode 100644
index 0000000000..5e694ff1a5
--- /dev/null
+++ b/jena-arq/testing/ARQ/Extra/expr-triple-term.ttl
@@ -0,0 +1,4 @@
+PREFIX : <http://example/>
+
+:s1 :p "s1" .
+:s2 :p :s2 .
diff --git a/jena-arq/testing/ARQ/Extra/manifest.ttl
b/jena-arq/testing/ARQ/Extra/manifest.ttl
index 8695534f65..4948f6e001 100644
--- a/jena-arq/testing/ARQ/Extra/manifest.ttl
+++ b/jena-arq/testing/ARQ/Extra/manifest.ttl
@@ -44,4 +44,11 @@
qt:data <data-count-distinct-expr.ttl> ] ;
mf:result <count-distinct-expr.srj>
]
+ [ mf:name "expr-triple-term" ;
+ rdf:type mfx:TestQuery ;
+ mf:action
+ [ qt:query <expr-triple-term.rq> ;
+ qt:data <expr-triple-term.ttl> ] ;
+ mf:result <expr-triple-term.srj>
+ ]
).