diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/util/URIUtil.java b/core/model/src/main/java/org/eclipse/rdf4j/model/util/URIUtil.java
index e3495f23d43..8fb9789c0df 100644
--- a/core/model/src/main/java/org/eclipse/rdf4j/model/util/URIUtil.java
+++ b/core/model/src/main/java/org/eclipse/rdf4j/model/util/URIUtil.java
@@ -228,6 +228,19 @@ public static boolean isValidLocalName(String name) {
for (int i = 1; i < name.length(); i++) {
if (!isNameChar(name.charAt(i))) {
+
+ // PLX
+ if (name.charAt(i) == '%') {
+ continue;
+ } else if (name.charAt(i) == '\\') {
+ if (i + 1 < name.length() && isPN_LOCAL_ESC(name.substring(i, i + 2))) {
+ i++;
+ continue;
+ } else {
+ return false;
+ }
+ }
+
return false;
}
@@ -341,7 +354,7 @@ private static boolean isNameStartChar(int codePoint) {
* @return true
if the supplied code point represents a valid name char, false
otherwise.
*/
private static boolean isNameChar(int codePoint) {
- return isPN_CHARS(codePoint) || codePoint == '.' || codePoint == ':' | codePoint == '\\' || codePoint == '%';
+ return isPN_CHARS(codePoint) || codePoint == '.' || codePoint == ':';
}
/**
diff --git a/core/model/src/test/java/org/eclipse/rdf4j/model/util/URIUtilTest.java b/core/model/src/test/java/org/eclipse/rdf4j/model/util/URIUtilTest.java
index 767ef29ae09..f8ade38b236 100644
--- a/core/model/src/test/java/org/eclipse/rdf4j/model/util/URIUtilTest.java
+++ b/core/model/src/test/java/org/eclipse/rdf4j/model/util/URIUtilTest.java
@@ -108,5 +108,6 @@ public void isValidLocalName() {
assertFalse(URIUtil.isValidLocalName("foo\tbar"));
assertFalse(URIUtil.isValidLocalName("foo\nbar"));
assertFalse(URIUtil.isValidLocalName("*foobar"));
+ assertTrue(URIUtil.isValidLocalName("fo\\'obar"));
}
}
diff --git a/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/SyntaxTreeBuilderTokenManager.java b/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/SyntaxTreeBuilderTokenManager.java
index 7844df6e4b5..4e48ce7b458 100644
--- a/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/SyntaxTreeBuilderTokenManager.java
+++ b/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/SyntaxTreeBuilderTokenManager.java
@@ -2296,7 +2296,7 @@ private int jjMoveNfa_0_curCharLessThan64(int startsAt, int i, int kind) {
}
break;
case 82:
- if ((0xa800ff7e00000000L & l) != 0L) {
+ if ((0xa800fffa00000000L & l) != 0L) {
jjCheckNAddStates(44, 47);
}
break;
@@ -2326,12 +2326,12 @@ private int jjMoveNfa_0_curCharLessThan64(int startsAt, int i, int kind) {
}
break;
case 88:
- if ((0xa800ff7e00000000L & l) != 0L && kind > 146) {
+ if ((0xa800fffa00000000L & l) != 0L && kind > 146) {
kind = 146;
}
break;
case 90:
- if ((0xa800ff7e00000000L & l) == 0L) {
+ if ((0xa800fffa00000000L & l) == 0L) {
break;
}
if (kind > 146) {
diff --git a/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/sparql.jjt b/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/sparql.jjt
index 1c1fc5eaf65..83f93871829 100644
--- a/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/sparql.jjt
+++ b/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/sparql.jjt
@@ -345,7 +345,7 @@ TOKEN:
| <#PN_LOCAL: ( | ":" | | ) ( ( | "." | ":" | )* ( | ":" | ) )?>
| <#PLX: | >
| <#PERCENT: "%" >
-| <#PN_LOCAL_ESC: "\\" [ "_", "~", ".", "-", "!", "$", "&", "\"", "(", ")", "*", "+", ",", ";", "=", "/", "?", "#", "@", "%" ]>
+| <#PN_LOCAL_ESC: "\\" [ "_", "~", ".", "-", "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=", "/", "?", "#", "@", "%" ]>
| <#VARNAME: ( | ) ()*>
|
| >">
diff --git a/core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLParserTest.java b/core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLParserTest.java
index 81912e2b320..fa963633783 100644
--- a/core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLParserTest.java
+++ b/core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLParserTest.java
@@ -976,6 +976,32 @@ public void testGroupByProjectionHandling_function() {
verifySerializable(parsedQuery.getTupleExpr());
}
+ @Test
+ public void testApostrophe() {
+ String query = "PREFIX rdf: \n" +
+ "select * where { \n" +
+ " rdf:Test\\'s ?p1 ?o1\n" +
+ "}";
+
+ HashSet customPrefixes = new HashSet<>();
+ SPARQLParser parser = new SPARQLParser(customPrefixes);
+
+ parser.parseQuery(query, null);
+ }
+
+ @Test
+ public void testApostropheInsertData() {
+ String query = "PREFIX rdf: \n" +
+ "INSERT DATA { \n" +
+ " rdf:Test\\'s a .\n" +
+ "}";
+
+ HashSet customPrefixes = new HashSet<>();
+ SPARQLParser parser = new SPARQLParser(customPrefixes);
+
+ parser.parseUpdate(query, null);
+ }
+
private AggregateFunctionFactory buildDummyFactory() {
return new AggregateFunctionFactory() {
@Override
diff --git a/core/rio/trig/src/test/resources/testcases/trig/trig-syntax-minimal-whitespace-01.trig b/core/rio/trig/src/test/resources/testcases/trig/trig-syntax-minimal-whitespace-01.trig
index f53451f8759..b7f3f441d14 100644
--- a/core/rio/trig/src/test/resources/testcases/trig/trig-syntax-minimal-whitespace-01.trig
+++ b/core/rio/trig/src/test/resources/testcases/trig/trig-syntax-minimal-whitespace-01.trig
@@ -19,3 +19,5 @@ d:.
_:s{:s :p :o .:s :p"Alice".:s :p _:o.}
:{: : :}{: : :}:{: : :}
:{():()}{():[]}:{[]:[]}
+{b:a\'s a :Foo}
+
diff --git a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleUtil.java b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleUtil.java
index b7b9985449f..9ce214265e3 100644
--- a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleUtil.java
+++ b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleUtil.java
@@ -13,6 +13,7 @@
import java.util.Arrays;
import org.eclipse.rdf4j.common.text.ASCIIUtil;
+import org.eclipse.rdf4j.model.util.URIUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -366,41 +367,7 @@ public static boolean isPN_LOCAL_ESC(String name) {
}
public static boolean isPN_LOCAL(String name) {
- // Empty names are legal
- if (name.isEmpty()) {
- return true;
- }
-
- if (!isPN_CHARS_U(name.charAt(0)) && name.charAt(0) != ':' && !ASCIIUtil.isNumber(name.charAt(0))
- && !isPLX_START(name)) {
- logger.debug("PN_LOCAL was not valid (start characters invalid) i=" + 0 + " nextchar="
- + name.charAt(0) + " name=" + name);
- return false;
- }
-
- if (!isNameStartChar(name.charAt(0))) {
- logger.debug("name was not valid (start character invalid) i=" + 0 + " nextchar=" + name.charAt(0)
- + " name=" + name);
- return false;
- }
-
- for (int i = 1; i < name.length(); i++) {
- if (!isNameChar(name.charAt(i))) {
- logger.debug("name was not valid (intermediate character invalid) i=" + i + " nextchar="
- + name.charAt(i) + " name=" + name);
- return false;
- }
-
- // Check if the percent encoding was less than two characters from the
- // end of the prefix, in which case it is invalid
- if (name.charAt(i) == '%' && (name.length() - i) < 3) {
- logger.debug("name was not valid (short percent escape) i=" + i + " nextchar=" + name.charAt(i)
- + " name=" + name);
- return false;
- }
- }
-
- return true;
+ return URIUtil.isValidLocalName(name);
}
// public static boolean isLegalName(String name) {
diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleUtilTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleUtilTest.java
index d884ca41496..279bf5b5e77 100644
--- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleUtilTest.java
+++ b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleUtilTest.java
@@ -229,6 +229,7 @@ public final void testIsPN_LOCAL() {
assertFalse(TurtleUtil.isPN_LOCAL("foo\tbar"));
assertFalse(TurtleUtil.isPN_LOCAL("foo\nbar"));
assertFalse(TurtleUtil.isPN_LOCAL("*foobar"));
+ assertTrue(TurtleUtil.isPN_LOCAL("foo\\'bar"));
}
/**
diff --git a/core/rio/turtle/src/test/resources/test-newlines.ttl b/core/rio/turtle/src/test/resources/test-newlines.ttl
index 677f2d33622..86b88ace9e5 100644
--- a/core/rio/turtle/src/test/resources/test-newlines.ttl
+++ b/core/rio/turtle/src/test/resources/test-newlines.ttl
@@ -5,7 +5,8 @@
ex:a a ex:Foo .
ex:b a ex:Foo .
ex:b ex:value '''^M'''.
-ex:c
+ex:c
:foo ex:Foo .
+rdf:Test\'s a ex:Foo .
ex:a ex:value 1.0 .
ex:a ex:value 3.0 .
diff --git a/e2e/package-lock.json b/e2e/package-lock.json
index 4f552816923..69bda428af6 100644
--- a/e2e/package-lock.json
+++ b/e2e/package-lock.json
@@ -9,32 +9,34 @@
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
- "@playwright/test": "^1.39.0",
- "@types/node": "^20.8.7"
+ "@playwright/test": "^1.49.0",
+ "@types/node": "^22.10.1"
}
},
"node_modules/@playwright/test": {
- "version": "1.39.0",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz",
- "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==",
+ "version": "1.49.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.0.tgz",
+ "integrity": "sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "playwright": "1.39.0"
+ "playwright": "1.49.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/@types/node": {
- "version": "20.8.7",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz",
- "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==",
+ "version": "22.10.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz",
+ "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "undici-types": "~5.25.1"
+ "undici-types": "~6.20.0"
}
},
"node_modules/fsevents": {
@@ -43,6 +45,7 @@
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -52,59 +55,62 @@
}
},
"node_modules/playwright": {
- "version": "1.39.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz",
- "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==",
+ "version": "1.49.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.0.tgz",
+ "integrity": "sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.39.0"
+ "playwright-core": "1.49.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
- "version": "1.39.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz",
- "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==",
+ "version": "1.49.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.0.tgz",
+ "integrity": "sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==",
"dev": true,
+ "license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/undici-types": {
- "version": "5.25.3",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz",
- "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==",
- "dev": true
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "license": "MIT"
}
},
"dependencies": {
"@playwright/test": {
- "version": "1.39.0",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz",
- "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==",
+ "version": "1.49.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.0.tgz",
+ "integrity": "sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==",
"dev": true,
"requires": {
- "playwright": "1.39.0"
+ "playwright": "1.49.0"
}
},
"@types/node": {
- "version": "20.8.7",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz",
- "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==",
+ "version": "22.10.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz",
+ "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==",
"dev": true,
"requires": {
- "undici-types": "~5.25.1"
+ "undici-types": "~6.20.0"
}
},
"fsevents": {
@@ -115,25 +121,25 @@
"optional": true
},
"playwright": {
- "version": "1.39.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz",
- "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==",
+ "version": "1.49.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.0.tgz",
+ "integrity": "sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==",
"dev": true,
"requires": {
"fsevents": "2.3.2",
- "playwright-core": "1.39.0"
+ "playwright-core": "1.49.0"
}
},
"playwright-core": {
- "version": "1.39.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz",
- "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==",
+ "version": "1.49.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.0.tgz",
+ "integrity": "sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==",
"dev": true
},
"undici-types": {
- "version": "5.25.3",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz",
- "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==",
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true
}
}
diff --git a/e2e/package.json b/e2e/package.json
index 5d2cea305d4..0665994aef6 100644
--- a/e2e/package.json
+++ b/e2e/package.json
@@ -8,7 +8,7 @@
"author": "",
"license": "ISC",
"devDependencies": {
- "@playwright/test": "^1.39.0",
- "@types/node": "^20.8.7"
+ "@playwright/test": "^1.49.0",
+ "@types/node": "^22.10.1"
}
}
diff --git a/e2e/run.sh b/e2e/run.sh
index 8fb93afce7e..f5a1b35f54e 100755
--- a/e2e/run.sh
+++ b/e2e/run.sh
@@ -12,9 +12,11 @@
set -e
+npm install
+
for APP_SERVER in tomcat jetty; do
export APP_SERVER
-
+
cd ..
cd docker
./run.sh
@@ -38,16 +40,16 @@ for APP_SERVER in tomcat jetty; do
cd ..
cd docker
- ./shutdown.sh
+ ./shutdown.sh
# test for error code
if [ $status_npx -ne 0 ] ; then
echo "Error in E2E test for $APP_SERVER"
exit $status_npx
fi
-
+
echo "E2E test for $APP_SERVER OK"
-
+
# don't redo the whole build process just for making another docker image
export SKIP_BUILD="skip"
done