imbajin commented on code in PR #833:
URL:
https://github.com/apache/hugegraph-toolchain/pull/833#discussion_r4350417987
##########
hugegraph-hubble/hubble-be/src/main/java/org/apache/hugegraph/util/ReadOnlyGremlin.java:
##########
@@ -65,13 +143,183 @@ public static void validate(String query) {
if (!"V".equals(start) && !"E".equals(start)) {
throw invalid();
}
- parser.arguments(0);
- parser.chain(STEPS, 0);
+ List<Step> steps = new ArrayList<>();
+ steps.add(new Step(start, parser.arguments(0), 0));
+ parser.chain(STEPS.keySet(), 0, steps);
parser.consume(';');
parser.whitespace();
if (parser.position != query.length()) {
throw invalid();
}
+ return new Traversal(steps, query.length());
+ }
+
+ private enum Output {
+ PRESERVE, EXPAND, REDUCE, COLLECT, LIMIT, CONSUME
+ }
+
+ static final class Traversal {
+
+ private final List<Step> steps;
+ private final int endPosition;
+
+ private Traversal(List<Step> steps, int endPosition) {
+ this.steps = List.copyOf(steps);
+ this.endPosition = endPosition;
+ }
+
+ int limitPosition(boolean preview, int limit) {
+ // Preview limits include the sentinel row used to report
truncation.
+ BigInteger previewSize = BigInteger.valueOf((long) limit - 1);
+ Analysis result = this.analyze(previewSize);
+ if (preview && result.largeCollection) {
+ throw new
ExternalException("gremlin.preview.collection_requires_async", previewSize);
+ }
+ return !result.singleResult && (preview || result.bound == null) ?
result.position : -1;
+ }
+
+ private Analysis analyze(BigInteger previewSize) {
+ BigInteger bound = null;
+ boolean singleResult = false;
+ boolean largeCollection = false;
+ boolean nestedCollection = false;
+ int position = this.endPosition;
+ for (int i = 0; i < this.steps.size(); i++) {
+ Step step = this.steps.get(i);
+ switch (STEPS.get(step.name)) {
+ case CONSUME:
+ // Cap the traversal before its final consumer,
preserving
+ // the List/Set/value/boolean result type. Further
methods
+ // would operate on materialized results, outside this
grammar.
+ if (i != this.steps.size() - 1) {
+ return new Analysis(-1, bound, true, false);
+ }
+ position = step.dotPosition;
+ if ("hasNext".equals(step.name)) {
+ largeCollection = false;
+ nestedCollection = false;
+ }
+ break;
+ case EXPAND:
+ bound = null;
+ singleResult = false;
+ largeCollection = false;
+ break;
+ case REDUCE:
+ largeCollection = false;
+ nestedCollection = false;
+ if (!step.localScope()) {
+ bound = BigInteger.ONE;
+ singleResult = true;
+ }
+ break;
+ case COLLECT:
+ // The keyed group overloads accumulate a side effect
+ // while passing each input traverser through.
+ if (("group".equals(step.name) ||
"groupCount".equals(step.name)) &&
+ !step.arguments.isEmpty()) {
+ break;
+ }
+ if (!step.localScope()) {
+ // A single List/Map can still download an entire
+ // graph. A later outer limit cannot shrink its
input.
+ largeCollection |= bound == null ||
bound.compareTo(previewSize) > 0;
+ // group() values are collections; unfolding its
Map
+ // returns entries that retain those complete
values.
+ nestedCollection |= "group".equals(step.name) &&
largeCollection;
Review Comment:
The specific double-fold counterexample reported here is repaired at
7a6f3af6672d1c5f7ea4dae57820b117daad17c5. Independent bounded
parser/TinkerGraph checks confirmed rejection while preserving the checked safe
controls. Resolving this specific finding does not establish overall preview
completeness, current CI success, or full acceptance; the broader review
remains incomplete.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]