diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5b70f5e1c..2a7b043e7 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -7,7 +7,7 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: matrix: diff --git a/CHANGELOG.md b/CHANGELOG.md index 026d4d09a..ce4bebb29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 2.24 [2023-12-14] + +### Improvements +- `allFields` mode to Measurement annotation [PR #972](https://github.com/influxdata/influxdb-java/pull/972) +- Support generic POJO super classes [PR #980](https://github.com/influxdata/influxdb-java/pull/980) + ## 2.23 [2022-07-07] ### Improvements diff --git a/QUERY_BUILDER.md b/QUERY_BUILDER.md index 5f500b8e4..d84e6d255 100644 --- a/QUERY_BUILDER.md +++ b/QUERY_BUILDER.md @@ -588,3 +588,19 @@ Query select = select().raw("an expression on select").from(dbName, "cpu").where ```sqlite-psql SELECT an expression on select FROM h2o_feet WHERE an expression as condition; ``` + +Binding parameters + +If your Query is based on user input, it is good practice to use parameter binding to avoid [injection attacks](https://en.wikipedia.org/wiki/SQL_injection). +You can create queries with parameter binding: + +```java +Query query = select().from(DATABASE,"h2o_feet").where(gt("water_level", FunctionFactory.placeholder("level"))) + .bindParameter("level", 8); +``` + +```sqlite-psql +SELECT * FROM h2o_feet WHERE water_level > $level; +``` + +The values of bindParameter() calls are bound to the placeholders in the query (`level`). diff --git a/pom.xml b/pom.xml index da1f4f9ab..b38781972 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.influxdb influxdb-java jar - 2.24 + 2.25 influxdb java bindings Java API to access the InfluxDB REST API http://www.influxdb.org @@ -24,7 +24,7 @@ scm:git:git@github.com:influxdata/influxdb-java.git scm:git:git@github.com:influxdata/influxdb-java.git git@github.com:influxdata/influxdb-java.git - influxdb-java-2.24 + influxdb-java-2.25 @@ -80,7 +80,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 1.8 1.8 @@ -89,7 +89,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.2 + 3.2.5 org.apache.maven.plugins @@ -274,7 +274,7 @@ org.assertj assertj-core - 3.24.2 + 3.25.2 test @@ -308,7 +308,7 @@ org.msgpack msgpack-core - 0.9.6 + 0.9.8 diff --git a/src/main/java/org/influxdb/dto/BoundParameterQuery.java b/src/main/java/org/influxdb/dto/BoundParameterQuery.java index 0c7b08b90..1f197289e 100644 --- a/src/main/java/org/influxdb/dto/BoundParameterQuery.java +++ b/src/main/java/org/influxdb/dto/BoundParameterQuery.java @@ -1,77 +1,9 @@ package org.influxdb.dto; -import com.squareup.moshi.JsonWriter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.influxdb.InfluxDBIOException; - -import okio.Buffer; - public final class BoundParameterQuery extends Query { - private final Map params = new HashMap<>(); - private BoundParameterQuery(final String command, final String database) { - super(command, database, true); - } - - public String getParameterJsonWithUrlEncoded() { - try { - String jsonParameterObject = createJsonObject(params); - String urlEncodedJsonParameterObject = encode(jsonParameterObject); - return urlEncodedJsonParameterObject; - } catch (IOException e) { - throw new InfluxDBIOException(e); - } - } - - private String createJsonObject(final Map parameterMap) throws IOException { - Buffer b = new Buffer(); - JsonWriter writer = JsonWriter.of(b); - writer.beginObject(); - for (Entry pair : parameterMap.entrySet()) { - String name = pair.getKey(); - Object value = pair.getValue(); - if (value instanceof Number) { - Number number = (Number) value; - writer.name(name).value(number); - } else if (value instanceof String) { - writer.name(name).value((String) value); - } else if (value instanceof Boolean) { - writer.name(name).value((Boolean) value); - } else { - writer.name(name).value(String.valueOf(value)); - } - } - writer.endObject(); - return b.readString(Charset.forName("utf-8")); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + params.hashCode(); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - BoundParameterQuery other = (BoundParameterQuery) obj; - if (!params.equals(other.params)) { - return false; - } - return true; + super(command, database); } public static class QueryBuilder { @@ -93,7 +25,7 @@ public QueryBuilder bind(final String placeholder, final Object value) { if (query == null) { query = new BoundParameterQuery(influxQL, null); } - query.params.put(placeholder, value); + query.bindParameter(placeholder, value); return this; } diff --git a/src/main/java/org/influxdb/dto/Query.java b/src/main/java/org/influxdb/dto/Query.java index 5c4921b8c..ebed08e7e 100644 --- a/src/main/java/org/influxdb/dto/Query.java +++ b/src/main/java/org/influxdb/dto/Query.java @@ -1,8 +1,18 @@ package org.influxdb.dto; +import com.squareup.moshi.JsonWriter; +import okio.Buffer; +import org.influxdb.InfluxDBIOException; +import org.influxdb.querybuilder.Appendable; + +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; /** * Represents a Query against Influxdb. @@ -15,6 +25,7 @@ public class Query { private final String command; private final String database; private final boolean requiresPost; + protected final Map params = new HashMap<>(); /** * @param command the query command @@ -68,38 +79,43 @@ public boolean requiresPost() { return requiresPost; } - @SuppressWarnings("checkstyle:avoidinlineconditionals") - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((command == null) ? 0 : command.hashCode()); - result = prime * result - + ((database == null) ? 0 : database.hashCode()); - return result; + public Query bindParameter(final String placeholder, final Object value) { + params.put(placeholder, value); + return this; + } + + public boolean hasBoundParameters() { + return !params.isEmpty(); + } + + public String getParameterJsonWithUrlEncoded() { + try { + String jsonParameterObject = createJsonObject(params); + String urlEncodedJsonParameterObject = encode(jsonParameterObject); + return urlEncodedJsonParameterObject; + } catch (IOException e) { + throw new InfluxDBIOException(e); + } } - @SuppressWarnings("checkstyle:needbraces") @Override - public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Query other = (Query) obj; - if (command == null) { - if (other.command != null) - return false; - } else if (!command.equals(other.command)) + public boolean equals(final Object o) { + if (o == null || getClass() != o.getClass()) { return false; - if (database == null) { - if (other.database != null) - return false; - } else if (!database.equals(other.database)) - return false; - return true; + } + + Query query = (Query) o; + return Objects.equals(command, query.command) && Objects.equals(database, query.database) && params.equals( + query.params); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = Objects.hashCode(command); + result = prime * result + Objects.hashCode(database); + result = prime * result + params.hashCode(); + return result; } /** @@ -115,4 +131,30 @@ public static String encode(final String command) { throw new IllegalStateException("Every JRE must support UTF-8", e); } } + + private String createJsonObject(final Map parameterMap) throws IOException { + Buffer b = new Buffer(); + JsonWriter writer = JsonWriter.of(b); + writer.beginObject(); + for (Map.Entry pair : parameterMap.entrySet()) { + String name = pair.getKey(); + Object value = pair.getValue(); + if (value instanceof Number) { + Number number = (Number) value; + writer.name(name).value(number); + } else if (value instanceof String) { + writer.name(name).value((String) value); + } else if (value instanceof Boolean) { + writer.name(name).value((Boolean) value); + } else if (value instanceof Appendable) { + StringBuilder stringBuilder = new StringBuilder(); + ((Appendable) value).appendTo(stringBuilder); + writer.name(name).value(stringBuilder.toString()); + } else { + writer.name(name).value(String.valueOf(value)); + } + } + writer.endObject(); + return b.readString(Charset.forName("utf-8")); + } } diff --git a/src/main/java/org/influxdb/impl/InfluxDBImpl.java b/src/main/java/org/influxdb/impl/InfluxDBImpl.java index 825e0708a..23427a23d 100644 --- a/src/main/java/org/influxdb/impl/InfluxDBImpl.java +++ b/src/main/java/org/influxdb/impl/InfluxDBImpl.java @@ -16,7 +16,6 @@ import org.influxdb.InfluxDBException; import org.influxdb.InfluxDBIOException; import org.influxdb.dto.BatchPoints; -import org.influxdb.dto.BoundParameterQuery; import org.influxdb.dto.Point; import org.influxdb.dto.Pong; import org.influxdb.dto.Query; @@ -637,13 +636,17 @@ public void query(final Query query, final int chunkSize, final BiConsumer onNext, final Runnable onComplete, final Consumer onFailure) { Call call; - if (query instanceof BoundParameterQuery) { - BoundParameterQuery boundParameterQuery = (BoundParameterQuery) query; - call = this.influxDBService.query(getDatabase(query), query.getCommandWithUrlEncoded(), chunkSize, - boundParameterQuery.getParameterJsonWithUrlEncoded()); + if (query.hasBoundParameters()) { + if (query.requiresPost()) { + call = this.influxDBService.postQuery(getDatabase(query), query.getCommandWithUrlEncoded(), chunkSize, + query.getParameterJsonWithUrlEncoded()); + } else { + call = this.influxDBService.query(getDatabase(query), query.getCommandWithUrlEncoded(), chunkSize, + query.getParameterJsonWithUrlEncoded()); + } } else { if (query.requiresPost()) { - call = this.influxDBService.query(getDatabase(query), query.getCommandWithUrlEncoded(), chunkSize, null); + call = this.influxDBService.postQuery(getDatabase(query), query.getCommandWithUrlEncoded(), chunkSize); } else { call = this.influxDBService.query(getDatabase(query), query.getCommandWithUrlEncoded(), chunkSize); } @@ -716,18 +719,21 @@ public void onFailure(final Call call, final Throwable t) { @Override public QueryResult query(final Query query, final TimeUnit timeUnit) { Call call; - if (query instanceof BoundParameterQuery) { - BoundParameterQuery boundParameterQuery = (BoundParameterQuery) query; - call = this.influxDBService.query(getDatabase(query), - TimeUtil.toTimePrecision(timeUnit), query.getCommandWithUrlEncoded(), - boundParameterQuery.getParameterJsonWithUrlEncoded()); + if (query.hasBoundParameters()) { + if (query.requiresPost()) { + call = this.influxDBService.postQuery(getDatabase(query), TimeUtil.toTimePrecision(timeUnit), + query.getCommandWithUrlEncoded(), query.getParameterJsonWithUrlEncoded()); + } else { + call = this.influxDBService.query(getDatabase(query), TimeUtil.toTimePrecision(timeUnit), + query.getCommandWithUrlEncoded(), query.getParameterJsonWithUrlEncoded()); + } } else { if (query.requiresPost()) { - call = this.influxDBService.query(getDatabase(query), - TimeUtil.toTimePrecision(timeUnit), query.getCommandWithUrlEncoded(), null); + call = this.influxDBService.postQuery(getDatabase(query), + TimeUtil.toTimePrecision(timeUnit), query.getCommandWithUrlEncoded()); } else { call = this.influxDBService.query(getDatabase(query), - TimeUtil.toTimePrecision(timeUnit), query.getCommandWithUrlEncoded()); + TimeUtil.toTimePrecision(timeUnit), query.getCommandWithUrlEncoded(), null); } } return executeQuery(call); @@ -788,10 +794,14 @@ public boolean databaseExists(final String name) { */ private Call callQuery(final Query query) { Call call; - if (query instanceof BoundParameterQuery) { - BoundParameterQuery boundParameterQuery = (BoundParameterQuery) query; + if (query.hasBoundParameters()) { + if (query.requiresPost()) { call = this.influxDBService.postQuery(getDatabase(query), query.getCommandWithUrlEncoded(), - boundParameterQuery.getParameterJsonWithUrlEncoded()); + query.getParameterJsonWithUrlEncoded()); + } else { + call = this.influxDBService.query(getDatabase(query), null, query.getCommandWithUrlEncoded(), + query.getParameterJsonWithUrlEncoded()); + } } else { if (query.requiresPost()) { call = this.influxDBService.postQuery(getDatabase(query), query.getCommandWithUrlEncoded()); diff --git a/src/main/java/org/influxdb/impl/InfluxDBService.java b/src/main/java/org/influxdb/impl/InfluxDBService.java index ce7a811b4..061a76615 100644 --- a/src/main/java/org/influxdb/impl/InfluxDBService.java +++ b/src/main/java/org/influxdb/impl/InfluxDBService.java @@ -47,12 +47,7 @@ public Call writePoints(@Query(DB) String database, @GET("query") public Call query(@Query(DB) String db, - @Query(EPOCH) String epoch, @Query(value = Q, encoded = true) String query); - - @POST("query") - @FormUrlEncoded - public Call query(@Query(DB) String db, - @Query(EPOCH) String epoch, @Field(value = Q, encoded = true) String query, + @Query(EPOCH) String epoch, @Query(value = Q, encoded = true) String query, @Query(value = PARAMS, encoded = true) String params); @GET("query") @@ -66,9 +61,26 @@ public Call postQuery(@Query(DB) String db, @POST("query") @FormUrlEncoded - public Call postQuery(@Query(DB) String db, + public Call postQuery(@Query(DB) String db, @Query(EPOCH) String epoch, + @Field(value = Q, encoded = true) String query); + + @POST("query") + @FormUrlEncoded + public Call postQuery(@Query(DB) String db, @Query(EPOCH) String epoch, @Field(value = Q, encoded = true) String query, @Query(value = PARAMS, encoded = true) String params); + @Streaming + @POST("query?chunked=true") + @FormUrlEncoded + public Call postQuery(@Query(DB) String db, @Field(value = Q, encoded = true) String query, + @Query(CHUNK_SIZE) int chunkSize); + + @Streaming + @POST("query?chunked=true") + @FormUrlEncoded + public Call postQuery(@Query(DB) String db, @Field(value = Q, encoded = true) String query, + @Query(CHUNK_SIZE) int chunkSize, @Query(value = PARAMS, encoded = true) String params); + @POST("query") @FormUrlEncoded public Call postQuery(@Field(value = Q, encoded = true) String query); @@ -79,8 +91,7 @@ public Call query(@Query(DB) String db, @Query(value = Q, encoded @Query(CHUNK_SIZE) int chunkSize); @Streaming - @POST("query?chunked=true") - @FormUrlEncoded - public Call query(@Query(DB) String db, @Field(value = Q, encoded = true) String query, + @GET("query?chunked=true") + public Call query(@Query(DB) String db, @Query(value = Q, encoded = true) String query, @Query(CHUNK_SIZE) int chunkSize, @Query(value = PARAMS, encoded = true) String params); } diff --git a/src/main/java/org/influxdb/querybuilder/Appender.java b/src/main/java/org/influxdb/querybuilder/Appender.java index 3dab5c02f..8c7e34bfd 100644 --- a/src/main/java/org/influxdb/querybuilder/Appender.java +++ b/src/main/java/org/influxdb/querybuilder/Appender.java @@ -62,6 +62,8 @@ public static StringBuilder appendValue(final Object value, final StringBuilder stringBuilder.append(')'); } else if (value instanceof Column) { appendName(((Column) value).getName(), stringBuilder); + } else if (value instanceof Placeholder) { + stringBuilder.append('$').append(((Placeholder) value).getName()); } else if (value instanceof String) { stringBuilder.append("'").append(value).append("'"); } else if (value != null) { diff --git a/src/main/java/org/influxdb/querybuilder/FunctionFactory.java b/src/main/java/org/influxdb/querybuilder/FunctionFactory.java index 19541c46a..ba5bfaba3 100644 --- a/src/main/java/org/influxdb/querybuilder/FunctionFactory.java +++ b/src/main/java/org/influxdb/querybuilder/FunctionFactory.java @@ -61,6 +61,10 @@ public static Object column(final String name) { return new Column(name); } + public static Object placeholder(final String name) { + return new Placeholder(name); + } + private static void convertToColumns(final Object... arguments) { for (int i = 0; i < arguments.length; i++) { arguments[i] = convertToColumn(arguments[i]); diff --git a/src/main/java/org/influxdb/querybuilder/Placeholder.java b/src/main/java/org/influxdb/querybuilder/Placeholder.java new file mode 100644 index 000000000..8b21cd880 --- /dev/null +++ b/src/main/java/org/influxdb/querybuilder/Placeholder.java @@ -0,0 +1,14 @@ +package org.influxdb.querybuilder; + +public class Placeholder { + + private final String name; + + Placeholder(final String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/test/java/org/influxdb/querybuilder/api/BuiltQueryTest.java b/src/test/java/org/influxdb/querybuilder/api/BuiltQueryTest.java index 2f9565add..1fcadfd74 100644 --- a/src/test/java/org/influxdb/querybuilder/api/BuiltQueryTest.java +++ b/src/test/java/org/influxdb/querybuilder/api/BuiltQueryTest.java @@ -10,10 +10,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import org.influxdb.dto.Query; +import org.influxdb.querybuilder.FunctionFactory; import org.influxdb.querybuilder.RawText; import org.influxdb.querybuilder.Where; import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; +@RunWith(JUnitPlatform.class) public class BuiltQueryTest { private static final String DATABASE = "testdb"; @@ -973,4 +977,12 @@ public void multipleDatabaseBackReferenceing() { assertEquals(query.getDatabase(), select.getDatabase()); } + @Test + public void testBoundParameters() { + Query query = select().column("a").from(DATABASE, "b") + .where(eq("c", FunctionFactory.placeholder("d"))).bindParameter("d", 3); + assertEquals("SELECT a FROM b WHERE c = $d;", query.getCommand()); + assertEquals(Query.encode("{\"d\":3}"), query.getParameterJsonWithUrlEncoded()); + assertEquals(DATABASE, query.getDatabase()); + } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy