From d14a4b69ab8622927495f03a43a8077786177639 Mon Sep 17 00:00:00 2001 From: Marko Budiselic Date: Wed, 12 Jul 2017 20:17:26 +0200 Subject: [PATCH] Max Query Size Summary: Query Size Limit in Python, Java, JavaScript Reviewers: mferencevic, mislav.bradac, teon.banek Reviewed By: mferencevic, teon.banek Subscribers: pullbot, buda Differential Revision: https://phabricator.memgraph.io/D508 --- docs/user_technical/quick-start.md | 2 +- tests/drivers/java/{test.java => Basic.java} | 2 +- tests/drivers/java/MaxQueryLength.java | 59 +++++++++++++++++++ tests/drivers/java/run.sh | 9 ++- .../drivers/javascript/{test.js => basic.js} | 0 tests/drivers/javascript/max_query_length.js | 51 ++++++++++++++++ tests/drivers/javascript/run.sh | 8 ++- tests/drivers/python/{test.py => basic.py} | 0 tests/drivers/python/max_query_length.py | 39 ++++++++++++ tests/drivers/python/run.sh | 9 +-- 10 files changed, 169 insertions(+), 10 deletions(-) rename tests/drivers/java/{test.java => Basic.java} (98%) create mode 100644 tests/drivers/java/MaxQueryLength.java rename tests/drivers/javascript/{test.js => basic.js} (100%) create mode 100644 tests/drivers/javascript/max_query_length.js rename tests/drivers/python/{test.py => basic.py} (100%) create mode 100644 tests/drivers/python/max_query_length.py diff --git a/docs/user_technical/quick-start.md b/docs/user_technical/quick-start.md index 00253c81e..ed321794d 100644 --- a/docs/user_technical/quick-start.md +++ b/docs/user_technical/quick-start.md @@ -224,7 +224,7 @@ to remove in future versions. The maximum length of a query that can be sent from a driver in Python is `16378` characters, from a driver in Java `8184` and from a driver in -JavaScript `1373` characters. +JavaScript `1392` characters. #### Multiple-Query Transactions diff --git a/tests/drivers/java/test.java b/tests/drivers/java/Basic.java similarity index 98% rename from tests/drivers/java/test.java rename to tests/drivers/java/Basic.java index ef777ab90..3ca311be5 100644 --- a/tests/drivers/java/test.java +++ b/tests/drivers/java/Basic.java @@ -3,7 +3,7 @@ import org.neo4j.driver.v1.types.*; import static org.neo4j.driver.v1.Values.parameters; import java.util.*; -public class test { +public class Basic { public static void main(String[] args) { Config config = Config.build().withoutEncryption().toConfig(); Driver driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic( "neo4j", "1234" ), config ); diff --git a/tests/drivers/java/MaxQueryLength.java b/tests/drivers/java/MaxQueryLength.java new file mode 100644 index 000000000..7b8ac817a --- /dev/null +++ b/tests/drivers/java/MaxQueryLength.java @@ -0,0 +1,59 @@ +/** + * Determines how long could be a query executed + * from Java driver. + * + * Performs binary search until the maximum possible + * query size has found. + */ + +import java.util.*; + +import org.neo4j.driver.v1.*; +import org.neo4j.driver.v1.types.*; +import static org.neo4j.driver.v1.Values.parameters; + +public class MaxQueryLength { + public static void main(String[] args) { + // init driver + Config config = Config.build().withoutEncryption().toConfig(); + Driver driver = GraphDatabase.driver("bolt://localhost:7687", + AuthTokens.basic( "", "" ), + config); + // init query + int property_size = 0; + int min_len = 1; + int max_len = 100000; + String query_template = "CREATE (n {name:\"%s\"})"; + int template_size = query_template.length() - 2; // because of %s + + // binary search + while (true) { + property_size = (max_len + min_len) / 2; + try (Session session = driver.session()) { + String property_value = new String(new char[property_size]) + .replace('\0', 'a'); + String query = String.format(query_template, property_value); + session.run(query).consume(); + if (min_len == max_len || property_size + 1 > max_len) { + break; + } + min_len = property_size + 1; + } + catch (Exception e) { + System.out.println(String.format( + "Query length: %d; Error: %s", + property_size + template_size, e)); + max_len = property_size - 1; + } + } + + // final result + System.out.println( + String.format("\nThe max length of a query executed from " + + "Java driver is: %s\n", + property_size + template_size)); + + // cleanup + driver.close(); + } +} diff --git a/tests/drivers/java/run.sh b/tests/drivers/java/run.sh index 7ed961a2e..fe98e5a39 100755 --- a/tests/drivers/java/run.sh +++ b/tests/drivers/java/run.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + JAVA=java JAVAC=javac @@ -19,5 +21,8 @@ if [ ! -f $DRIVER ]; then wget -O $DRIVER http://central.maven.org/maven2/org/neo4j/driver/neo4j-java-driver/1.3.1/neo4j-java-driver-1.3.1.jar || exit 1 fi -javac -classpath .:$DRIVER test.java || exit 1 -java -classpath .:$DRIVER test || exit 1 +javac -classpath .:$DRIVER Basic.java +java -classpath .:$DRIVER Basic + +javac -classpath .:$DRIVER MaxQueryLength.java +java -classpath .:$DRIVER MaxQueryLength diff --git a/tests/drivers/javascript/test.js b/tests/drivers/javascript/basic.js similarity index 100% rename from tests/drivers/javascript/test.js rename to tests/drivers/javascript/basic.js diff --git a/tests/drivers/javascript/max_query_length.js b/tests/drivers/javascript/max_query_length.js new file mode 100644 index 000000000..2851f149f --- /dev/null +++ b/tests/drivers/javascript/max_query_length.js @@ -0,0 +1,51 @@ +// Determines how long could be a query executed +// from JavaScript driver. +// +// Performs binary search until the maximum possible +// query size has found. + +// init driver +var neo4j = require('neo4j-driver').v1; +var driver = neo4j.driver("bolt://localhost:7687", + neo4j.auth.basic("", ""), + { encrypted: 'ENCRYPTION_OFF' }); + +// init state +var property_size = 0; +var min_len = 1; +var max_len = 1000000; + +// hacking with JS and callbacks concept +function serial_execution() { + var next_size = [Math.floor((min_len + max_len) / 2)]; + setInterval(function() { + if (next_size.length > 0) { + property_size = next_size.pop(); + var query = "CREATE (n {name:\"" + + (new Array(property_size)).join("a")+ "\"})"; + var session = driver.session(); + session.run(query, {}).then(function (result) { + console.log("Success with the query length " + query.length); + if (min_len == max_len || property_size + 1 > max_len) { + console.log("\nThe max length of a query from JS driver is: " + + query.length + "\n"); + session.close(); + driver.close(); + process.exit(0); + } + min_len = property_size + 1; + next_size.push(Math.floor((min_len + max_len) / 2)); + }).catch(function (error) { + console.log("Failure with the query length " + query.length); + max_len = property_size - 1; + next_size.push(Math.floor((min_len + max_len) / 2)); + }).then(function(){ + session.close(); + }); + } + }, 100); +} + +// execution +console.log("\nDetermine how long can be a query sent from JavaScript driver."); +serial_execution(); // I don't like JavaScript diff --git a/tests/drivers/javascript/run.sh b/tests/drivers/javascript/run.sh index a490cbbeb..29cde8130 100755 --- a/tests/drivers/javascript/run.sh +++ b/tests/drivers/javascript/run.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + NODE=nodejs NPM=npm @@ -13,5 +15,7 @@ if ! which $NPM >/dev/null; then exit 1 fi -$NPM install neo4j-driver || exit 1 -$NODE test.js || exit 1 +$NPM install neo4j-driver + +$NODE basic.js +$NODE max_query_length.js diff --git a/tests/drivers/python/test.py b/tests/drivers/python/basic.py similarity index 100% rename from tests/drivers/python/test.py rename to tests/drivers/python/basic.py diff --git a/tests/drivers/python/max_query_length.py b/tests/drivers/python/max_query_length.py new file mode 100644 index 000000000..5cf48130b --- /dev/null +++ b/tests/drivers/python/max_query_length.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from neo4j.v1 import GraphDatabase, basic_auth + +driver = GraphDatabase.driver("bolt://localhost:7687", + auth=basic_auth("", ""), + encrypted=False) + +query_template = 'CREATE (n {name:"%s"})' +template_size = len(query_template) - 2 # because of %s +min_len = 1 +max_len = 1000000 + +# binary search because we have to find the maximum size (in number of chars) +# of a query that can be executed via driver +while True: + assert min_len > 0 and max_len > 0, \ + "The lengths have to be positive values! If this happens something" \ + " is terrible wrong with min & max lengths OR the database" \ + " isn't available." + property_size = (max_len + min_len) // 2 + try: + driver.session().run(query_template % ("a" * property_size)).consume() + if min_len == max_len or property_size + 1 > max_len: + break + min_len = property_size + 1 + except Exception as e: + print("Query size %s is too big!" % (template_size + property_size)) + max_len = property_size - 1 + +assert property_size == max_len, "max_len probably has to be increased!" + +print("\nThe max length of a query from Python driver is: %s\n" % + (template_size + property_size)) + +# sessions are not closed bacause all sessions that are +# executed with wrong query size might be broken +driver.close() diff --git a/tests/drivers/python/run.sh b/tests/drivers/python/run.sh index 3b4d5a008..ab6899ce2 100755 --- a/tests/drivers/python/run.sh +++ b/tests/drivers/python/run.sh @@ -1,12 +1,12 @@ #!/bin/bash +set -e + VIRTUALENV=virtualenv PIP=pip PYTHON=python WORKING_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -set -e - cd ${WORKING_DIR} # system check @@ -17,11 +17,12 @@ fi # setup virtual environment if [ ! -d "ve3" ]; then - virtualenv -p python3 ve3 + virtualenv -p python3 ve3 || exit 1 fi source ve3/bin/activate $PIP install --upgrade pip $PIP install neo4j-driver # execute test -$PYTHON test.py +$PYTHON basic.py +$PYTHON max_query_length.py