Skip to content

Commit 20f6546

Browse files
authored
DRILL-8244: HTTP_Request Not Passing Down Config Variables (#2571)
* Initial Commit * Addressed review comments, removed logging statement
1 parent 570ce63 commit 20f6546

3 files changed

Lines changed: 113 additions & 4 deletions

File tree

contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/udfs/HttpHelperFunctions.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,6 @@ public static class HttpGetFromStoragePluginFunction implements DrillSimpleFunc
135135

136136
@Override
137137
public void setup() {
138-
jsonLoaderBuilder = new org.apache.drill.exec.store.easy.json.loader.JsonLoaderImpl.JsonLoaderBuilder()
139-
.resultSetLoader(loader)
140-
.standardOptions(options);
141-
142138
String schemaPath = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start, rawInput.end, rawInput.buffer);
143139
// Get the plugin name and endpoint name
144140
String[] parts = schemaPath.split("\\.");
@@ -153,10 +149,15 @@ public void setup() {
153149
drillbitContext,
154150
pluginName
155151
);
152+
156153
endpointConfig = org.apache.drill.exec.store.http.util.SimpleHttp.getEndpointConfig(
157154
endpointName,
158155
plugin.getConfig()
159156
);
157+
158+
// Add JSON configuration from Storage plugin, if present.
159+
jsonLoaderBuilder = org.apache.drill.exec.store.http.udfs.HttpUdfUtils.setupJsonBuilder(endpointConfig, loader, options);
160+
160161
}
161162

162163
@Override
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.drill.exec.store.http.udfs;
20+
21+
import org.apache.commons.lang3.StringUtils;
22+
import org.apache.drill.exec.physical.resultSet.ResultSetLoader;
23+
import org.apache.drill.exec.server.options.OptionManager;
24+
import org.apache.drill.exec.store.easy.json.loader.JsonLoaderImpl.JsonLoaderBuilder;
25+
import org.apache.drill.exec.store.easy.json.loader.JsonLoaderOptions;
26+
import org.apache.drill.exec.store.http.HttpApiConfig;
27+
import org.apache.drill.exec.store.http.HttpJsonOptions;
28+
import org.slf4j.Logger;
29+
import org.slf4j.LoggerFactory;
30+
31+
public class HttpUdfUtils {
32+
33+
private static final Logger logger = LoggerFactory.getLogger(HttpUdfUtils.class);
34+
35+
public static JsonLoaderBuilder setupJsonBuilder(HttpApiConfig endpointConfig, ResultSetLoader loader, OptionManager options) {
36+
loader.setTargetRowCount(1);
37+
// Add JSON configuration from Storage plugin, if present.
38+
HttpJsonOptions jsonOptions = endpointConfig.jsonOptions();
39+
JsonLoaderBuilder jsonLoaderBuilder = new JsonLoaderBuilder()
40+
.resultSetLoader(loader)
41+
.maxRows(1)
42+
.standardOptions(options);
43+
44+
// Add data path if present
45+
if (StringUtils.isNotEmpty(endpointConfig.dataPath())) {
46+
jsonLoaderBuilder.dataPath(endpointConfig.dataPath());
47+
}
48+
49+
if (jsonOptions != null) {
50+
// Add options from endpoint configuration to jsonLoader
51+
JsonLoaderOptions jsonLoaderOptions = jsonOptions.getJsonOptions(options);
52+
jsonLoaderBuilder.options(jsonLoaderOptions);
53+
54+
// Add provided schema if present
55+
if (jsonOptions.schema() != null) {
56+
logger.debug("Found schema: {}", jsonOptions.schema());
57+
jsonLoaderBuilder.providedSchema(jsonOptions.schema());
58+
}
59+
}
60+
return jsonLoaderBuilder;
61+
}
62+
}

contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFFunctions.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.drill.common.logical.StoragePluginConfig.AuthMode;
2626
import org.apache.drill.common.logical.security.PlainCredentialsProvider;
2727
import org.apache.drill.common.types.TypeProtos;
28+
import org.apache.drill.common.types.TypeProtos.MinorType;
2829
import org.apache.drill.common.util.DrillFileUtils;
2930
import org.apache.drill.exec.physical.impl.project.ProjectMemoryManager;
3031
import org.apache.drill.exec.physical.impl.project.ProjectRecordBatch;
@@ -64,6 +65,7 @@ public class TestHttpUDFFunctions extends ClusterTest {
6465

6566
private static final int MOCK_SERVER_PORT = 47771;
6667
private static String TEST_JSON_RESPONSE;
68+
private static String TEST_JSON_PAGE1;
6769
private static String DUMMY_URL = "http://localhost:" + MOCK_SERVER_PORT;
6870
protected static LogFixture logFixture;
6971
private final static Level CURRENT_LOG_LEVEL = Level.INFO;
@@ -80,6 +82,7 @@ public static void setup() throws Exception {
8082
.build();
8183
startCluster(ClusterFixture.builder(dirTestWatcher));
8284
TEST_JSON_RESPONSE = Files.asCharSource(DrillFileUtils.getResourceAsFile("/data/simple.json"), Charsets.UTF_8).read();
85+
TEST_JSON_PAGE1 = Files.asCharSource(DrillFileUtils.getResourceAsFile("/data/p1.json"), Charsets.UTF_8).read();
8386

8487
HttpApiConfig mockGithubWithDuplicateParam = HttpApiConfig.builder()
8588
.url(String.format("%s/orgs/{org}/repos", DUMMY_URL))
@@ -89,8 +92,27 @@ public static void setup() throws Exception {
8992
.requireTail(false)
9093
.build();
9194

95+
TupleMetadata simpleSchema = new SchemaBuilder()
96+
.addNullable("col_1", MinorType.FLOAT8)
97+
.addNullable("col_2", MinorType.FLOAT8)
98+
.addNullable("col_3", MinorType.FLOAT8)
99+
.build();
100+
101+
HttpJsonOptions jsonOptions = new HttpJsonOptions.HttpJsonOptionsBuilder()
102+
.schema(simpleSchema)
103+
.build();
104+
105+
HttpApiConfig basicJson = HttpApiConfig.builder()
106+
.url(String.format("%s/json", DUMMY_URL))
107+
.method("get")
108+
.jsonOptions(jsonOptions)
109+
.requireTail(false)
110+
.inputType("json")
111+
.build();
112+
92113
Map<String, HttpApiConfig> configs = new HashMap<>();
93114
configs.put("github", mockGithubWithDuplicateParam);
115+
configs.put("basicJson", basicJson);
94116

95117
HttpStoragePluginConfig mockStorageConfigWithWorkspace =
96118
new HttpStoragePluginConfig(false, configs, 2, "globaluser", "globalpass", "",
@@ -101,6 +123,30 @@ public static void setup() throws Exception {
101123
cluster.defineStoragePlugin("local", mockStorageConfigWithWorkspace);
102124
}
103125

126+
@Test
127+
public void testProvidedSchema() throws Exception {
128+
String sql = "SELECT http_request('local.basicJson') as data FROM (values(1))";
129+
try (MockWebServer server = startServer()) {
130+
server.enqueue(new MockResponse().setResponseCode(200).setBody(TEST_JSON_PAGE1));
131+
RowSet results = client.queryBuilder().sql(sql).rowSet();
132+
133+
TupleMetadata expectedSchema = new SchemaBuilder()
134+
.addMap("data")
135+
.addNullable("col_1", MinorType.FLOAT8)
136+
.addNullable("col_2", MinorType.FLOAT8)
137+
.addNullable("col_3", MinorType.FLOAT8)
138+
.resumeSchema()
139+
.build();
140+
141+
RowSet expected = new RowSetBuilder(client.allocator(), expectedSchema)
142+
.addRow(singleMap(
143+
mapValue(1.0, 2.0, 3.0)))
144+
.build();
145+
146+
RowSetUtilities.verify(expected, results);
147+
}
148+
}
149+
104150
@Test
105151
public void testHttpGetWithNoParams() throws Exception {
106152
try (MockWebServer server = startServer()) {

0 commit comments

Comments
 (0)