in server/pxf-service/src/main/java/org/greenplum/pxf/service/HttpRequestParser.java [80:243]
public RequestContext parseRequest(MultiValueMap<String, String> requestHeaders, RequestContext.RequestType requestType) {
RequestMap params = new RequestMap(requestHeaders, headerDecoder);
if (LOG.isDebugEnabled()) {
// Logging only keys to prevent sensitive data to be logged
LOG.debug("Parsing request parameters: " + params.keySet());
}
RequestContext context = new RequestContext();
// fill the Request-scoped RequestContext with parsed values
context.setClientApiVersion(
params.removeProperty("PXF-API-VERSION", ERROR_MESSAGE_HINT));
if (!apiVersionChecker.isCompatible(getServerApiVersion(), context.getClientApiVersion())) {
throw new PxfRuntimeException(
String.format(ERROR_MESSAGE_TEMPLATE, getServerApiVersion(), context.getClientApiVersion()), ERROR_MESSAGE_HINT);
}
// whether we are in a fragmenter, read_bridge, or write_bridge scenario
context.setRequestType(requestType);
// first of all, set profile and enrich parameters with information from specified profile
String profileUserValue = params.removeUserProperty("PROFILE");
String profile = profileUserValue == null ? null : profileUserValue.toLowerCase();
context.setProfile(profile);
addProfilePlugins(profile, params);
// Ext table uses system property FORMAT for wire serialization format
String wireFormat = params.removeProperty("FORMAT");
context.setOutputFormat(OutputFormat.valueOf(wireFormat));
// FDW uses user property FORMAT to indicate format of data
String format = params.removeUserProperty("FORMAT");
format = StringUtils.isNotBlank(format) ? format : context.inferFormatName();
context.setFormat(format);
context.setAccessor(params.removeUserProperty("ACCESSOR"));
context.setAggType(EnumAggregationType.getAggregationType(params.removeOptionalProperty("AGG-TYPE")));
context.setDataSource(params.removeProperty("DATA-DIR"));
String filterString = params.removeOptionalProperty("FILTER");
String hasFilter = params.removeProperty("HAS-FILTER");
if (filterString != null) {
context.setFilterString(filterString);
} else if ("1".equals(hasFilter)) {
LOG.info("Original query has filter, but it was not propagated to PXF");
}
context.setDataEncoding(charsetUtils.forName(params.removeProperty("DATA-ENCODING")));
context.setDatabaseEncoding(charsetUtils.forName(params.removeProperty("DATABASE-ENCODING")));
context.setFragmenter(params.removeUserProperty("FRAGMENTER"));
context.setHost(params.removeProperty("URL-HOST"));
context.setMetadata(params.removeUserProperty("METADATA"));
context.setPort(params.removeIntProperty("URL-PORT"));
context.setProfileScheme(params.removeUserProperty(PROFILE_SCHEME));
context.setProtocol(params.removeUserProperty("PROTOCOL"));
context.setRemoteLogin(params.removeOptionalProperty("REMOTE-USER"));
context.setRemoteSecret(params.removeOptionalProperty("REMOTE-PASS"));
context.setResolver(params.removeUserProperty("RESOLVER"));
context.setSegmentId(params.removeIntProperty("SEGMENT-ID"));
context.setServerName(params.removeUserProperty("SERVER"));
context.setSchemaName(params.removeProperty("SCHEMA-NAME"));
context.setTableName(params.removeProperty("TABLE-NAME"));
// An optional CONFIG value specifies the name of the server
// configuration directory, if not provided the config is the server name
String config = params.removeUserProperty("CONFIG");
context.setConfig(StringUtils.isNotBlank(config) ? config : context.getServerName());
String maxFrags = params.removeUserProperty("STATS-MAX-FRAGMENTS");
if (!StringUtils.isBlank(maxFrags)) {
context.setStatsMaxFragments(Integer.parseInt(maxFrags));
}
String sampleRatioStr = params.removeUserProperty("STATS-SAMPLE-RATIO");
if (!StringUtils.isBlank(sampleRatioStr)) {
context.setStatsSampleRatio(Float.parseFloat(sampleRatioStr));
}
context.setTotalSegments(params.removeIntProperty("SEGMENT-COUNT"));
context.setTransactionId(params.removeProperty("XID"));
// parse tuple description
parseTupleDescription(params, context);
if (context.getOutputFormat() == OutputFormat.TEXT) {
// parse CSV format information
parseGreenplumCSV(params, context);
// Only single column tables support 'OFF' delimiter
if (context.getTupleDescription().size() != 1 && context.getGreenplumCSV().getDelimiter() == null) {
throw new IllegalArgumentException(String.format("using no delimiter is only possible for a single column table. %d columns found", context.getTupleDescription().size()));
}
}
context.setGpSessionId(params.removeIntProperty("SESSION-ID"));
context.setGpCommandCount(params.removeIntProperty("COMMAND-COUNT"));
context.setUser(params.removeProperty("USER"));
// Store alignment for global use as a system property
System.setProperty("greenplum.alignment", params.removeProperty("ALIGNMENT"));
Map<String, String> optionMappings = null;
// prepare addition configuration properties if profile was specified
if (StringUtils.isNotBlank(profile)) {
optionMappings = pluginConf.getOptionMappings(profile);
}
// use empty map for convenience instead of null
if (optionMappings == null) {
optionMappings = Collections.emptyMap();
}
Map<String, String> additionalConfigProps = new HashMap<>();
// Iterate over the remaining properties
// we clone the keyset to prevent concurrent modification exceptions
List<String> paramNames = new ArrayList<>(params.keySet());
for (String param : paramNames) {
if (StringUtils.startsWithIgnoreCase(param, RequestMap.USER_PROP_PREFIX)) {
// Add all left-over user properties as options
String optionName = param.toLowerCase().replace(RequestMap.USER_PROP_PREFIX_LOWERCASE, "");
String optionValue = params.removeUserProperty(optionName);
context.addOption(optionName, optionValue);
LOG.debug("Added option {} to request context", optionName);
// lookup if the option should also be applied as a config property
String propertyName = optionMappings.get(optionName);
if (StringUtils.isNotBlank(propertyName)) {
// if option has been provided by the user in the request, set the value
// of the corresponding configuration property
if (optionValue != null) {
additionalConfigProps.put(propertyName, optionValue);
// do not log property value as it might contain sensitive information
LOG.debug("Added extra config property {} from option {}", propertyName, optionName);
}
}
} else if (StringUtils.startsWithIgnoreCase(param, RequestMap.PROP_PREFIX)) {
// log debug for all left-over system properties
LOG.debug("Unused property {}", param);
}
}
context.setAdditionalConfigProps(additionalConfigProps);
context.setPluginConf(pluginConf);
// Call the protocol handler for any protocol-specific logic handling
if (StringUtils.isNotBlank(profile)) {
String handlerClassName = pluginConf.getHandler(profile);
Utilities.updatePlugins(context, handlerClassName);
}
// validate that the result has all required fields, and values are in valid ranges
context.validate();
return context;
}