mirror of https://github.com/apache/lucene.git
Merge branch 'jira/solr-8593'
This commit is contained in:
commit
bfeb4e7f84
|
@ -17,8 +17,6 @@ com.carrotsearch.randomizedtesting.version = 2.5.0
|
|||
/com.cybozu.labs/langdetect = 1.1-20120112
|
||||
/com.drewnoakes/metadata-extractor = 2.8.1
|
||||
|
||||
/com.facebook.presto/presto-parser = 0.122
|
||||
|
||||
com.fasterxml.jackson.core.version = 2.5.4
|
||||
/com.fasterxml.jackson.core/jackson-annotations = ${com.fasterxml.jackson.core.version}
|
||||
/com.fasterxml.jackson.core/jackson-core = ${com.fasterxml.jackson.core.version}
|
||||
|
@ -33,7 +31,7 @@ com.google.inject.guice.version = 3.0
|
|||
/com.google.inject.extensions/guice-servlet = ${com.google.inject.guice.version}
|
||||
/com.google.inject/guice = ${com.google.inject.guice.version}
|
||||
|
||||
/com.google.protobuf/protobuf-java = 2.5.0
|
||||
/com.google.protobuf/protobuf-java = 3.1.0
|
||||
/com.googlecode.juniversalchardet/juniversalchardet = 1.0.3
|
||||
/com.googlecode.mp4parser/isoparser = 1.1.18
|
||||
/com.healthmarketscience.jackcess/jackcess = 2.1.3
|
||||
|
@ -72,7 +70,6 @@ com.sun.jersey.version = 1.9
|
|||
/dom4j/dom4j = 1.6.1
|
||||
/hsqldb/hsqldb = 1.8.0.10
|
||||
/info.ganglia.gmetric4j/gmetric4j = 1.0.7
|
||||
/io.airlift/slice = 0.10
|
||||
|
||||
io.dropwizard.metrics.version = 3.1.2
|
||||
/io.dropwizard.metrics/metrics-core = ${io.dropwizard.metrics.version}
|
||||
|
@ -97,6 +94,7 @@ io.netty.netty-all.version = 4.0.36.Final
|
|||
/mecab/mecab-naist-jdic = 0.6.3b-20111013
|
||||
/net.arnx/jsonic = 1.2.7
|
||||
/net.bytebuddy/byte-buddy = 1.6.2
|
||||
/net.hydromatic/eigenbase-properties = 1.1.5
|
||||
/net.sf.ehcache/ehcache-core = 2.4.4
|
||||
/net.sf.saxon/Saxon-HE = 9.6.0-2
|
||||
/net.sourceforge.argparse4j/argparse4j = 0.4.3
|
||||
|
@ -106,6 +104,14 @@ io.netty.netty-all.version = 4.0.36.Final
|
|||
|
||||
/org.apache.ant/ant = 1.8.2
|
||||
/org.apache.avro/avro = 1.7.5
|
||||
|
||||
org.apache.calcite.avatica.version = 1.9.0
|
||||
/org.apache.calcite.avatica/avatica-core = ${org.apache.calcite.avatica.version}
|
||||
|
||||
org.apache.calcite.version = 1.11.0
|
||||
/org.apache.calcite/calcite-core = ${org.apache.calcite.version}
|
||||
/org.apache.calcite/calcite-linq4j = ${org.apache.calcite.version}
|
||||
|
||||
/org.apache.commons/commons-compress = 1.11
|
||||
/org.apache.commons/commons-exec = 1.3
|
||||
/org.apache.commons/commons-math3 = 3.4.1
|
||||
|
@ -243,6 +249,10 @@ org.codehaus.jackson.version = 1.9.13
|
|||
/org.codehaus.jackson/jackson-jaxrs = ${org.codehaus.jackson.version}
|
||||
/org.codehaus.jackson/jackson-mapper-asl = ${org.codehaus.jackson.version}
|
||||
|
||||
org.codehaus.janino.version = 2.7.6
|
||||
/org.codehaus.janino/commons-compiler = ${org.codehaus.janino.version}
|
||||
/org.codehaus.janino/janino = ${org.codehaus.janino.version}
|
||||
|
||||
/org.codehaus.woodstox/stax2-api = 3.1.4
|
||||
/org.codehaus.woodstox/woodstox-core-asl = 4.4.1
|
||||
/org.easymock/easymock = 3.0
|
||||
|
|
|
@ -60,8 +60,8 @@
|
|||
<dependency org="org.objenesis" name="objenesis" rev="${/org.objenesis/objenesis}" conf="test"/>
|
||||
|
||||
<dependency org="com.fasterxml.jackson.core" name="jackson-core" rev="${/com.fasterxml.jackson.core/jackson-core}" conf="compile"/>
|
||||
<dependency org="com.fasterxml.jackson.core" name="jackson-databind" rev="${/com.fasterxml.jackson.core/jackson-databind}" conf="test"/>
|
||||
<dependency org="com.fasterxml.jackson.core" name="jackson-annotations" rev="${/com.fasterxml.jackson.core/jackson-annotations}" conf="test"/>
|
||||
<dependency org="com.fasterxml.jackson.core" name="jackson-databind" rev="${/com.fasterxml.jackson.core/jackson-databind}" conf="compile"/>
|
||||
<dependency org="com.fasterxml.jackson.core" name="jackson-annotations" rev="${/com.fasterxml.jackson.core/jackson-annotations}" conf="compile"/>
|
||||
<dependency org="com.fasterxml.jackson.dataformat" name="jackson-dataformat-smile" rev="${/com.fasterxml.jackson.dataformat/jackson-dataformat-smile}" conf="compile"/>
|
||||
|
||||
|
||||
|
@ -142,10 +142,15 @@
|
|||
|
||||
<!-- StatsComponents percentiles Dependencies-->
|
||||
<dependency org="com.tdunning" name="t-digest" rev="${/com.tdunning/t-digest}" conf="compile->*"/>
|
||||
<!-- SQL Parser -->
|
||||
|
||||
<dependency org="com.facebook.presto" name="presto-parser" rev="${/com.facebook.presto/presto-parser}"/>
|
||||
<dependency org="io.airlift" name="slice" rev="${/io.airlift/slice}"/>
|
||||
<!-- SQL Parser -->
|
||||
<dependency org="org.apache.calcite" name="calcite-core" rev="${/org.apache.calcite/calcite-core}" conf="compile"/>
|
||||
<dependency org="org.apache.calcite" name="calcite-linq4j" rev="${/org.apache.calcite/calcite-linq4j}" conf="compile"/>
|
||||
<dependency org="org.apache.calcite.avatica" name="avatica-core" rev="${/org.apache.calcite.avatica/avatica-core}" conf="compile"/>
|
||||
<dependency org="net.hydromatic" name="eigenbase-properties" rev="${/net.hydromatic/eigenbase-properties}" conf="compile"/>
|
||||
<dependency org="org.codehaus.janino" name="janino" rev="${/org.codehaus.janino/janino}" conf="compile"/>
|
||||
<dependency org="org.codehaus.janino" name="commons-compiler" rev="${/org.codehaus.janino/commons-compiler}" conf="compile"/>
|
||||
<dependency org="com.google.protobuf" name="protobuf-java" rev="${/com.google.protobuf/protobuf-java}" conf="compile"/>
|
||||
|
||||
<exclude org="*" ext="*" matcher="regexp" type="${ivy.exclude.types}"/>
|
||||
</dependencies>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.jdbc.CalciteConnection;
|
||||
import org.apache.calcite.jdbc.Driver;
|
||||
import org.apache.calcite.schema.SchemaPlus;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* JDBC driver for Calcite Solr.
|
||||
*
|
||||
* <p>It accepts connect strings that start with "jdbc:calcitesolr:".</p>
|
||||
*/
|
||||
public class CalciteSolrDriver extends Driver {
|
||||
public final static String CONNECT_STRING_PREFIX = "jdbc:calcitesolr:";
|
||||
|
||||
private CalciteSolrDriver() {
|
||||
super();
|
||||
}
|
||||
|
||||
static {
|
||||
new CalciteSolrDriver().register();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConnectStringPrefix() {
|
||||
return CONNECT_STRING_PREFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection connect(String url, Properties info) throws SQLException {
|
||||
if(!this.acceptsURL(url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Connection connection = super.connect(url, info);
|
||||
CalciteConnection calciteConnection = (CalciteConnection) connection;
|
||||
final SchemaPlus rootSchema = calciteConnection.getRootSchema();
|
||||
|
||||
String schemaName = info.getProperty("zk");
|
||||
if(schemaName == null) {
|
||||
throw new SQLException("zk must be set");
|
||||
}
|
||||
rootSchema.add(schemaName, new SolrSchema(info));
|
||||
|
||||
// Set the default schema
|
||||
calciteConnection.setSchema(schemaName);
|
||||
|
||||
return connection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.solr.client.solrj.io.Tuple;
|
||||
import org.apache.solr.client.solrj.io.comp.StreamComparator;
|
||||
import org.apache.solr.client.solrj.io.stream.StreamContext;
|
||||
import org.apache.solr.client.solrj.io.stream.TupleStream;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.Explanation;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.StreamExplanation;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
class LimitStream extends TupleStream {
|
||||
|
||||
private final TupleStream stream;
|
||||
private final int limit;
|
||||
private int count;
|
||||
|
||||
LimitStream(TupleStream stream, int limit) {
|
||||
this.stream = stream;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public void open() throws IOException {
|
||||
this.stream.open();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
this.stream.close();
|
||||
}
|
||||
|
||||
public List<TupleStream> children() {
|
||||
List<TupleStream> children = new ArrayList<>();
|
||||
children.add(stream);
|
||||
return children;
|
||||
}
|
||||
|
||||
public StreamComparator getStreamSort(){
|
||||
return stream.getStreamSort();
|
||||
}
|
||||
|
||||
public void setStreamContext(StreamContext context) {
|
||||
stream.setStreamContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Explanation toExplanation(StreamFactory factory) throws IOException {
|
||||
|
||||
return new StreamExplanation(getStreamNodeId().toString())
|
||||
.withChildren(new Explanation[]{
|
||||
stream.toExplanation(factory)
|
||||
})
|
||||
.withFunctionName("SQL LIMIT")
|
||||
.withExpression("--non-expressible--")
|
||||
.withImplementingClass(this.getClass().getName())
|
||||
.withExpressionType(Explanation.ExpressionType.STREAM_DECORATOR);
|
||||
}
|
||||
|
||||
public Tuple read() throws IOException {
|
||||
++count;
|
||||
if(count > limit) {
|
||||
Map<String, String> fields = new HashMap<>();
|
||||
fields.put("EOF", "true");
|
||||
return new Tuple(fields);
|
||||
}
|
||||
|
||||
return stream.read();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.plan.RelOptCluster;
|
||||
import org.apache.calcite.plan.RelTraitSet;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.core.Aggregate;
|
||||
import org.apache.calcite.rel.core.AggregateCall;
|
||||
import org.apache.calcite.sql.SqlAggFunction;
|
||||
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
|
||||
import org.apache.calcite.util.ImmutableBitSet;
|
||||
import org.apache.calcite.util.Pair;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Implementation of {@link org.apache.calcite.rel.core.Aggregate} relational expression in Solr.
|
||||
*/
|
||||
class SolrAggregate extends Aggregate implements SolrRel {
|
||||
private static final List<SqlAggFunction> SUPPORTED_AGGREGATIONS = Arrays.asList(
|
||||
SqlStdOperatorTable.COUNT,
|
||||
SqlStdOperatorTable.SUM,
|
||||
SqlStdOperatorTable.SUM0,
|
||||
SqlStdOperatorTable.MIN,
|
||||
SqlStdOperatorTable.MAX,
|
||||
SqlStdOperatorTable.AVG
|
||||
);
|
||||
|
||||
SolrAggregate(
|
||||
RelOptCluster cluster,
|
||||
RelTraitSet traitSet,
|
||||
RelNode child,
|
||||
boolean indicator,
|
||||
ImmutableBitSet groupSet,
|
||||
List<ImmutableBitSet> groupSets,
|
||||
List<AggregateCall> aggCalls) {
|
||||
super(cluster, traitSet, child, indicator, groupSet, groupSets, aggCalls);
|
||||
assert getConvention() == SolrRel.CONVENTION;
|
||||
assert getConvention() == child.getConvention();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Aggregate copy(RelTraitSet traitSet, RelNode input,
|
||||
boolean indicator, ImmutableBitSet groupSet,
|
||||
List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
|
||||
return new SolrAggregate(getCluster(), traitSet, input, indicator, groupSet, groupSets, aggCalls);
|
||||
}
|
||||
|
||||
public void implement(Implementor implementor) {
|
||||
implementor.visitChild(0, getInput());
|
||||
|
||||
final List<String> inNames = SolrRules.solrFieldNames(getInput().getRowType());
|
||||
|
||||
|
||||
for(Pair<AggregateCall, String> namedAggCall : getNamedAggCalls()) {
|
||||
|
||||
|
||||
AggregateCall aggCall = namedAggCall.getKey();
|
||||
|
||||
Pair<String, String> metric = toSolrMetric(implementor, aggCall, inNames);
|
||||
implementor.addReverseAggMapping(namedAggCall.getValue(), metric.getKey().toLowerCase()+"("+metric.getValue()+")");
|
||||
implementor.addMetricPair(namedAggCall.getValue(), metric.getKey(), metric.getValue());
|
||||
if(aggCall.getName() == null) {
|
||||
implementor.addFieldMapping(namedAggCall.getValue(),
|
||||
aggCall.getAggregation().getName() + "(" + inNames.get(aggCall.getArgList().get(0)) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
for(int group : getGroupSet()) {
|
||||
String inName = inNames.get(group);
|
||||
implementor.addBucket(inName);
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<String, String> toSolrMetric(Implementor implementor, AggregateCall aggCall, List<String> inNames) {
|
||||
SqlAggFunction aggregation = aggCall.getAggregation();
|
||||
List<Integer> args = aggCall.getArgList();
|
||||
switch (args.size()) {
|
||||
case 0:
|
||||
if (aggregation.equals(SqlStdOperatorTable.COUNT)) {
|
||||
return new Pair<>(aggregation.getName(), "*");
|
||||
}
|
||||
case 1:
|
||||
String inName = inNames.get(args.get(0));
|
||||
String name = implementor.fieldMappings.getOrDefault(inName, inName);
|
||||
if(SUPPORTED_AGGREGATIONS.contains(aggregation)) {
|
||||
return new Pair<>(aggregation.getName(), name);
|
||||
}
|
||||
default:
|
||||
throw new AssertionError("Invalid aggregation " + aggregation + " with args " + args + " with names" + inNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End SolrAggregate.java
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.linq4j.Enumerator;
|
||||
import org.apache.solr.client.solrj.io.Tuple;
|
||||
import org.apache.solr.client.solrj.io.stream.TupleStream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
/** Enumerator that reads from a Solr collection. */
|
||||
class SolrEnumerator implements Enumerator<Object> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final TupleStream tupleStream;
|
||||
private final List<Map.Entry<String, Class>> fields;
|
||||
private Tuple current;
|
||||
private char sep = 31;
|
||||
|
||||
/** Creates a SolrEnumerator.
|
||||
*
|
||||
* @param tupleStream Solr TupleStream
|
||||
* @param fields Fields to get from each Tuple
|
||||
*/
|
||||
SolrEnumerator(TupleStream tupleStream, List<Map.Entry<String, Class>> fields) {
|
||||
this.tupleStream = tupleStream;
|
||||
try {
|
||||
this.tupleStream.open();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.fields = fields;
|
||||
this.current = null;
|
||||
}
|
||||
|
||||
/** Produce the next row from the results
|
||||
*
|
||||
* @return A new row from the results
|
||||
*/
|
||||
public Object current() {
|
||||
if (fields.size() == 1) {
|
||||
return this.getter(current, fields.get(0));
|
||||
} else {
|
||||
// Build an array with all fields in this row
|
||||
Object[] row = new Object[fields.size()];
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
row[i] = this.getter(current, fields.get(i));
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
|
||||
private Object getter(Tuple tuple, Map.Entry<String, Class> field) {
|
||||
Object val = tuple.get(field.getKey());
|
||||
|
||||
if(val == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class clazz = field.getValue();
|
||||
if(clazz.equals(Long.class)) {
|
||||
if(val instanceof Double) {
|
||||
return this.getRealVal(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
if(val instanceof ArrayList) {
|
||||
ArrayList arrayList = (ArrayList) val;
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
for(Object o : arrayList) {
|
||||
buf.append(sep);
|
||||
buf.append(o.toString());
|
||||
}
|
||||
val = buf.toString();
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private Object getRealVal(Object val) {
|
||||
// Check if Double is really a Long
|
||||
if(val instanceof Double) {
|
||||
Double doubleVal = (double) val;
|
||||
//make sure that double has no decimals and fits within Long
|
||||
if(doubleVal % 1 == 0 && doubleVal >= Long.MIN_VALUE && doubleVal <= Long.MAX_VALUE) {
|
||||
return doubleVal.longValue();
|
||||
}
|
||||
return doubleVal;
|
||||
}
|
||||
|
||||
// Wasn't a double so just return original Object
|
||||
return val;
|
||||
}
|
||||
|
||||
public boolean moveNext() {
|
||||
try {
|
||||
Tuple tuple = this.tupleStream.read();
|
||||
if (tuple.EOF) {
|
||||
return false;
|
||||
} else {
|
||||
current = tuple;
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("IOException", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if(this.tupleStream != null) {
|
||||
try {
|
||||
this.tupleStream.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.plan.*;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.core.Filter;
|
||||
import org.apache.calcite.rel.metadata.RelMetadataQuery;
|
||||
import org.apache.calcite.rex.RexCall;
|
||||
import org.apache.calcite.rex.RexInputRef;
|
||||
import org.apache.calcite.rex.RexLiteral;
|
||||
import org.apache.calcite.rex.RexNode;
|
||||
import org.apache.calcite.sql.SqlKind;
|
||||
import org.apache.calcite.util.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation of a {@link org.apache.calcite.rel.core.Filter} relational expression in Solr.
|
||||
*/
|
||||
class SolrFilter extends Filter implements SolrRel {
|
||||
SolrFilter(
|
||||
RelOptCluster cluster,
|
||||
RelTraitSet traitSet,
|
||||
RelNode child,
|
||||
RexNode condition) {
|
||||
super(cluster, traitSet, child, condition);
|
||||
assert getConvention() == SolrRel.CONVENTION;
|
||||
assert getConvention() == child.getConvention();
|
||||
}
|
||||
|
||||
@Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
|
||||
return super.computeSelfCost(planner, mq).multiplyBy(0.1);
|
||||
}
|
||||
|
||||
public SolrFilter copy(RelTraitSet traitSet, RelNode input, RexNode condition) {
|
||||
return new SolrFilter(getCluster(), traitSet, input, condition);
|
||||
}
|
||||
|
||||
public void implement(Implementor implementor) {
|
||||
implementor.visitChild(0, getInput());
|
||||
if(getInput() instanceof SolrAggregate) {
|
||||
HavingTranslator translator = new HavingTranslator(SolrRules.solrFieldNames(getRowType()), implementor.reverseAggMappings);
|
||||
String havingPredicate = translator.translateMatch(condition);
|
||||
implementor.setHavingPredicate(havingPredicate);
|
||||
} else {
|
||||
Translator translator = new Translator(SolrRules.solrFieldNames(getRowType()));
|
||||
String query = translator.translateMatch(condition);
|
||||
implementor.addQuery(query);
|
||||
implementor.setNegativeQuery(translator.negativeQuery);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Translator {
|
||||
|
||||
private final List<String> fieldNames;
|
||||
public boolean negativeQuery = true;
|
||||
|
||||
Translator(List<String> fieldNames) {
|
||||
this.fieldNames = fieldNames;
|
||||
}
|
||||
|
||||
private String translateMatch(RexNode condition) {
|
||||
if (condition.getKind().belongsTo(SqlKind.COMPARISON)) {
|
||||
return translateComparison(condition);
|
||||
} else if (condition.isA(SqlKind.AND)) {
|
||||
return "(" + translateAnd(condition) + ")";
|
||||
} else if (condition.isA(SqlKind.OR)) {
|
||||
return "(" + translateOr(condition) + ")";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String translateOr(RexNode condition) {
|
||||
List<String> ors = new ArrayList<>();
|
||||
for (RexNode node : RelOptUtil.disjunctions(condition)) {
|
||||
ors.add(translateMatch(node));
|
||||
}
|
||||
return String.join(" OR ", ors);
|
||||
}
|
||||
|
||||
private String translateAnd(RexNode node0) {
|
||||
List<String> andStrings = new ArrayList();
|
||||
List<String> notStrings = new ArrayList();
|
||||
|
||||
List<RexNode> ands = new ArrayList();
|
||||
List<RexNode> nots = new ArrayList();
|
||||
RelOptUtil.decomposeConjunction(node0, ands, nots);
|
||||
|
||||
|
||||
for (RexNode node : ands) {
|
||||
andStrings.add(translateMatch(node));
|
||||
}
|
||||
|
||||
String andString = String.join(" AND ", andStrings);
|
||||
|
||||
if (nots.size() > 0) {
|
||||
for (RexNode node : nots) {
|
||||
notStrings.add(translateMatch(node));
|
||||
}
|
||||
String notString = String.join(" NOT ", notStrings);
|
||||
return "(" + andString + ") NOT (" + notString + ")";
|
||||
} else {
|
||||
return andString;
|
||||
}
|
||||
}
|
||||
|
||||
private String translateComparison(RexNode node) {
|
||||
Pair<String, RexLiteral> binaryTranslated = null;
|
||||
if (((RexCall) node).getOperands().size() == 2) {
|
||||
binaryTranslated = translateBinary((RexCall) node);
|
||||
}
|
||||
|
||||
switch (node.getKind()) {
|
||||
case NOT:
|
||||
return "-" + translateComparison(((RexCall) node).getOperands().get(0));
|
||||
case EQUALS:
|
||||
String terms = binaryTranslated.getValue().toString().trim();
|
||||
terms = terms.replace("'","");
|
||||
if (!terms.startsWith("(") && !terms.startsWith("[") && !terms.startsWith("{")) {
|
||||
terms = "\"" + terms + "\"";
|
||||
}
|
||||
|
||||
String clause = binaryTranslated.getKey() + ":" + terms;
|
||||
this.negativeQuery = false;
|
||||
return clause;
|
||||
case NOT_EQUALS:
|
||||
return "-(" + binaryTranslated.getKey() + ":" + binaryTranslated.getValue() + ")";
|
||||
case LESS_THAN:
|
||||
this.negativeQuery = false;
|
||||
return "(" + binaryTranslated.getKey() + ": [ * TO " + binaryTranslated.getValue() + " })";
|
||||
case LESS_THAN_OR_EQUAL:
|
||||
this.negativeQuery = false;
|
||||
return "(" + binaryTranslated.getKey() + ": [ * TO " + binaryTranslated.getValue() + " ])";
|
||||
case GREATER_THAN:
|
||||
this.negativeQuery = false;
|
||||
return "(" + binaryTranslated.getKey() + ": { " + binaryTranslated.getValue() + " TO * ])";
|
||||
case GREATER_THAN_OR_EQUAL:
|
||||
this.negativeQuery = false;
|
||||
return "(" + binaryTranslated.getKey() + ": [ " + binaryTranslated.getValue() + " TO * ])";
|
||||
default:
|
||||
throw new AssertionError("cannot translate " + node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a call to a binary operator, reversing arguments if necessary.
|
||||
*/
|
||||
private Pair<String, RexLiteral> translateBinary(RexCall call) {
|
||||
List<RexNode> operands = call.getOperands();
|
||||
if (operands.size() != 2) {
|
||||
throw new AssertionError("Invalid number of arguments - " + operands.size());
|
||||
}
|
||||
final RexNode left = operands.get(0);
|
||||
final RexNode right = operands.get(1);
|
||||
final Pair<String, RexLiteral> a = translateBinary2(left, right);
|
||||
if (a != null) {
|
||||
return a;
|
||||
}
|
||||
final Pair<String, RexLiteral> b = translateBinary2(right, left);
|
||||
if (b != null) {
|
||||
return b;
|
||||
}
|
||||
throw new AssertionError("cannot translate call " + call);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a call to a binary operator. Returns whether successful.
|
||||
*/
|
||||
private Pair<String, RexLiteral> translateBinary2(RexNode left, RexNode right) {
|
||||
switch (right.getKind()) {
|
||||
case LITERAL:
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
final RexLiteral rightLiteral = (RexLiteral) right;
|
||||
switch (left.getKind()) {
|
||||
case INPUT_REF:
|
||||
final RexInputRef left1 = (RexInputRef) left;
|
||||
String name = fieldNames.get(left1.getIndex());
|
||||
return new Pair<>(name, rightLiteral);
|
||||
case CAST:
|
||||
return translateBinary2(((RexCall) left).operands.get(0), right);
|
||||
// case OTHER_FUNCTION:
|
||||
// String itemName = SolrRules.isItem((RexCall) left);
|
||||
// if (itemName != null) {
|
||||
// return translateOp2(op, itemName, rightLiteral);
|
||||
// }
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class HavingTranslator {
|
||||
|
||||
private final List<String> fieldNames;
|
||||
private Map<String,String> reverseAggMappings;
|
||||
|
||||
HavingTranslator(List<String> fieldNames, Map<String, String> reverseAggMappings) {
|
||||
this.fieldNames = fieldNames;
|
||||
this.reverseAggMappings = reverseAggMappings;
|
||||
}
|
||||
|
||||
private String translateMatch(RexNode condition) {
|
||||
if (condition.getKind().belongsTo(SqlKind.COMPARISON)) {
|
||||
return translateComparison(condition);
|
||||
} else if (condition.isA(SqlKind.AND)) {
|
||||
return translateAnd(condition);
|
||||
} else if (condition.isA(SqlKind.OR)) {
|
||||
return translateOr(condition);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String translateOr(RexNode condition) {
|
||||
List<String> ors = new ArrayList<>();
|
||||
for (RexNode node : RelOptUtil.disjunctions(condition)) {
|
||||
ors.add(translateMatch(node));
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("or(");
|
||||
int i = 0;
|
||||
for (i = 0; i < ors.size(); i++) {
|
||||
if (i > 0) {
|
||||
builder.append(",");
|
||||
}
|
||||
|
||||
builder.append(ors.get(i));
|
||||
}
|
||||
builder.append(")");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String translateAnd(RexNode node0) {
|
||||
List<String> andStrings = new ArrayList();
|
||||
List<String> notStrings = new ArrayList();
|
||||
|
||||
List<RexNode> ands = new ArrayList();
|
||||
List<RexNode> nots = new ArrayList();
|
||||
|
||||
RelOptUtil.decomposeConjunction(node0, ands, nots);
|
||||
|
||||
for (RexNode node : ands) {
|
||||
andStrings.add(translateMatch(node));
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("and(");
|
||||
for (int i = 0; i < andStrings.size(); i++) {
|
||||
if (i > 0) {
|
||||
builder.append(",");
|
||||
}
|
||||
|
||||
builder.append(andStrings.get(i));
|
||||
}
|
||||
builder.append(")");
|
||||
|
||||
|
||||
if (nots.size() > 0) {
|
||||
for (RexNode node : nots) {
|
||||
notStrings.add(translateMatch(node));
|
||||
}
|
||||
|
||||
StringBuilder notBuilder = new StringBuilder();
|
||||
for(int i=0; i< notStrings.size(); i++) {
|
||||
if(i > 0) {
|
||||
notBuilder.append(",");
|
||||
}
|
||||
notBuilder.append("not(");
|
||||
notBuilder.append(notStrings.get(i));
|
||||
notBuilder.append(")");
|
||||
}
|
||||
|
||||
return "and(" + builder.toString() + ","+ notBuilder.toString()+")";
|
||||
} else {
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String translateComparison(RexNode node) {
|
||||
Pair<String, RexLiteral> binaryTranslated = null;
|
||||
if (((RexCall) node).getOperands().size() == 2) {
|
||||
binaryTranslated = translateBinary((RexCall) node);
|
||||
}
|
||||
|
||||
switch (node.getKind()) {
|
||||
case EQUALS:
|
||||
String terms = binaryTranslated.getValue().toString().trim();
|
||||
String clause = "eq(" + binaryTranslated.getKey() + "," + terms + ")";
|
||||
return clause;
|
||||
case NOT_EQUALS:
|
||||
return "not(eq(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue() + "))";
|
||||
case LESS_THAN:
|
||||
return "lt(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue() + ")";
|
||||
case LESS_THAN_OR_EQUAL:
|
||||
return "lteq(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue() + ")";
|
||||
case GREATER_THAN:
|
||||
return "gt(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue() + ")";
|
||||
case GREATER_THAN_OR_EQUAL:
|
||||
return "gteq(" + binaryTranslated.getKey() + "," + binaryTranslated.getValue() + ")";
|
||||
default:
|
||||
throw new AssertionError("cannot translate " + node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a call to a binary operator, reversing arguments if necessary.
|
||||
*/
|
||||
private Pair<String, RexLiteral> translateBinary(RexCall call) {
|
||||
List<RexNode> operands = call.getOperands();
|
||||
if (operands.size() != 2) {
|
||||
throw new AssertionError("Invalid number of arguments - " + operands.size());
|
||||
}
|
||||
final RexNode left = operands.get(0);
|
||||
final RexNode right = operands.get(1);
|
||||
final Pair<String, RexLiteral> a = translateBinary2(left, right);
|
||||
|
||||
if (a != null) {
|
||||
if(reverseAggMappings.containsKey(a.getKey())) {
|
||||
return new Pair<String, RexLiteral>(reverseAggMappings.get(a.getKey()),a.getValue());
|
||||
}
|
||||
return a;
|
||||
}
|
||||
final Pair<String, RexLiteral> b = translateBinary2(right, left);
|
||||
if (b != null) {
|
||||
return b;
|
||||
}
|
||||
throw new AssertionError("cannot translate call " + call);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a call to a binary operator. Returns whether successful.
|
||||
*/
|
||||
private Pair<String, RexLiteral> translateBinary2(RexNode left, RexNode right) {
|
||||
switch (right.getKind()) {
|
||||
case LITERAL:
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
final RexLiteral rightLiteral = (RexLiteral) right;
|
||||
switch (left.getKind()) {
|
||||
case INPUT_REF:
|
||||
final RexInputRef left1 = (RexInputRef) left;
|
||||
String name = fieldNames.get(left1.getIndex());
|
||||
return new Pair<>(name, rightLiteral);
|
||||
case CAST:
|
||||
return translateBinary2(((RexCall) left).operands.get(0), right);
|
||||
// case OTHER_FUNCTION:
|
||||
// String itemName = SolrRules.isItem((RexCall) left);
|
||||
// if (itemName != null) {
|
||||
// return translateOp2(op, itemName, rightLiteral);
|
||||
// }
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.linq4j.tree.Types;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Builtin methods in the Solr adapter.
|
||||
*/
|
||||
enum SolrMethod {
|
||||
SOLR_QUERYABLE_QUERY(SolrTable.SolrQueryable.class,
|
||||
"query",
|
||||
List.class,
|
||||
String.class,
|
||||
List.class,
|
||||
List.class,
|
||||
List.class,
|
||||
String.class,
|
||||
String.class,
|
||||
String.class);
|
||||
|
||||
public final Method method;
|
||||
|
||||
SolrMethod(Class clazz, String methodName, Class... argumentTypes) {
|
||||
this.method = Types.lookupMethod(clazz, methodName, argumentTypes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.adapter.java.JavaTypeFactory;
|
||||
import org.apache.calcite.plan.RelOptCluster;
|
||||
import org.apache.calcite.plan.RelOptCost;
|
||||
import org.apache.calcite.plan.RelOptPlanner;
|
||||
import org.apache.calcite.plan.RelTraitSet;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.core.Project;
|
||||
import org.apache.calcite.rel.metadata.RelMetadataQuery;
|
||||
import org.apache.calcite.rel.type.RelDataType;
|
||||
import org.apache.calcite.rex.RexNode;
|
||||
import org.apache.calcite.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of {@link org.apache.calcite.rel.core.Project} relational expression in Solr.
|
||||
*/
|
||||
class SolrProject extends Project implements SolrRel {
|
||||
SolrProject(RelOptCluster cluster, RelTraitSet traitSet,
|
||||
RelNode input, List<? extends RexNode> projects, RelDataType rowType) {
|
||||
super(cluster, traitSet, input, projects, rowType);
|
||||
assert getConvention() == SolrRel.CONVENTION;
|
||||
assert getConvention() == input.getConvention();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project copy(RelTraitSet traitSet, RelNode input, List<RexNode> projects, RelDataType rowType) {
|
||||
return new SolrProject(getCluster(), traitSet, input, projects, rowType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
|
||||
return super.computeSelfCost(planner, mq).multiplyBy(0.1);
|
||||
}
|
||||
|
||||
public void implement(Implementor implementor) {
|
||||
implementor.visitChild(0, getInput());
|
||||
final SolrRules.RexToSolrTranslator translator = new SolrRules.RexToSolrTranslator(
|
||||
(JavaTypeFactory) getCluster().getTypeFactory(), SolrRules.solrFieldNames(getInput().getRowType()));
|
||||
for (Pair<RexNode, String> pair : getNamedProjects()) {
|
||||
final String name = pair.right;
|
||||
final String expr = pair.left.accept(translator);
|
||||
implementor.addFieldMapping(name, expr);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.plan.Convention;
|
||||
import org.apache.calcite.plan.RelOptTable;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.util.Pair;
|
||||
import org.apache.solr.client.solrj.io.ops.BooleanOperation;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Relational expression that uses Solr calling convention.
|
||||
*/
|
||||
interface SolrRel extends RelNode {
|
||||
void implement(Implementor implementor);
|
||||
|
||||
/** Calling convention for relational operations that occur in Solr. */
|
||||
Convention CONVENTION = new Convention.Impl("Solr", SolrRel.class);
|
||||
|
||||
/** Callback for the implementation process that converts a tree of {@link SolrRel} nodes into a Solr query. */
|
||||
class Implementor {
|
||||
final Map<String, String> fieldMappings = new HashMap<>();
|
||||
final Map<String, String> reverseAggMappings = new HashMap<>();
|
||||
String query = null;
|
||||
String havingPredicate;
|
||||
boolean negativeQuery;
|
||||
String limitValue = null;
|
||||
final List<Pair<String, String>> orders = new ArrayList<>();
|
||||
final List<String> buckets = new ArrayList<>();
|
||||
final List<Pair<String, String>> metricPairs = new ArrayList<>();
|
||||
|
||||
RelOptTable table;
|
||||
SolrTable solrTable;
|
||||
|
||||
void addFieldMapping(String key, String val) {
|
||||
if(key != null && !fieldMappings.containsKey(key)) {
|
||||
this.fieldMappings.put(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
void addReverseAggMapping(String key, String val) {
|
||||
if(key != null && !reverseAggMappings.containsKey(key)) {
|
||||
this.reverseAggMappings.put(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
void addQuery(String query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
void setNegativeQuery(boolean negativeQuery) {
|
||||
this.negativeQuery = negativeQuery;
|
||||
}
|
||||
|
||||
void addOrder(String column, String direction) {
|
||||
column = this.fieldMappings.getOrDefault(column, column);
|
||||
this.orders.add(new Pair<>(column, direction));
|
||||
}
|
||||
|
||||
void addBucket(String bucket) {
|
||||
bucket = this.fieldMappings.getOrDefault(bucket, bucket);
|
||||
this.buckets.add(bucket);
|
||||
}
|
||||
|
||||
void addMetricPair(String outName, String metric, String column) {
|
||||
column = this.fieldMappings.getOrDefault(column, column);
|
||||
this.metricPairs.add(new Pair<>(metric, column));
|
||||
|
||||
String metricIdentifier = metric.toLowerCase(Locale.ROOT) + "(" + column + ")";
|
||||
if(outName != null) {
|
||||
this.addFieldMapping(outName, metricIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
void setHavingPredicate(String havingPredicate) {
|
||||
this.havingPredicate = havingPredicate;
|
||||
}
|
||||
|
||||
|
||||
void setLimit(String limit) {
|
||||
limitValue = limit;
|
||||
}
|
||||
|
||||
void visitChild(int ordinal, RelNode input) {
|
||||
assert ordinal == 0;
|
||||
((SolrRel) input).implement(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.adapter.java.JavaTypeFactory;
|
||||
import org.apache.calcite.plan.*;
|
||||
import org.apache.calcite.rel.RelCollations;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.convert.ConverterRule;
|
||||
import org.apache.calcite.rel.core.Sort;
|
||||
import org.apache.calcite.rel.logical.LogicalAggregate;
|
||||
import org.apache.calcite.rel.logical.LogicalFilter;
|
||||
import org.apache.calcite.rel.logical.LogicalProject;
|
||||
import org.apache.calcite.rel.logical.LogicalSort;
|
||||
import org.apache.calcite.rel.type.RelDataType;
|
||||
import org.apache.calcite.rex.RexCall;
|
||||
import org.apache.calcite.rex.RexInputRef;
|
||||
import org.apache.calcite.rex.RexNode;
|
||||
import org.apache.calcite.rex.RexVisitorImpl;
|
||||
import org.apache.calcite.sql.SqlKind;
|
||||
import org.apache.calcite.sql.validate.SqlValidatorUtil;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Rules and relational operators for
|
||||
* {@link SolrRel#CONVENTION}
|
||||
* calling convention.
|
||||
*/
|
||||
class SolrRules {
|
||||
static final RelOptRule[] RULES = {
|
||||
SolrSortRule.SORT_RULE,
|
||||
SolrFilterRule.FILTER_RULE,
|
||||
SolrProjectRule.PROJECT_RULE,
|
||||
SolrAggregateRule.AGGREGATE_RULE,
|
||||
};
|
||||
|
||||
static List<String> solrFieldNames(final RelDataType rowType) {
|
||||
return SqlValidatorUtil.uniquify(
|
||||
new AbstractList<String>() {
|
||||
@Override
|
||||
public String get(int index) {
|
||||
return rowType.getFieldList().get(index).getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rowType.getFieldCount();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
/** Translator from {@link RexNode} to strings in Solr's expression language. */
|
||||
static class RexToSolrTranslator extends RexVisitorImpl<String> {
|
||||
private final JavaTypeFactory typeFactory;
|
||||
private final List<String> inFields;
|
||||
|
||||
RexToSolrTranslator(JavaTypeFactory typeFactory, List<String> inFields) {
|
||||
super(true);
|
||||
this.typeFactory = typeFactory;
|
||||
this.inFields = inFields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitInputRef(RexInputRef inputRef) {
|
||||
return inFields.get(inputRef.getIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitCall(RexCall call) {
|
||||
final List<String> strings = visitList(call.operands);
|
||||
if (call.getKind() == SqlKind.CAST) {
|
||||
return strings.get(0);
|
||||
}
|
||||
|
||||
return super.visitCall(call);
|
||||
}
|
||||
|
||||
private List<String> visitList(List<RexNode> list) {
|
||||
final List<String> strings = new ArrayList<>();
|
||||
for (RexNode node : list) {
|
||||
strings.add(node.accept(this));
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
|
||||
/** Base class for planner rules that convert a relational expression to Solr calling convention. */
|
||||
abstract static class SolrConverterRule extends ConverterRule {
|
||||
final Convention out = SolrRel.CONVENTION;
|
||||
|
||||
SolrConverterRule(Class<? extends RelNode> clazz, String description) {
|
||||
this(clazz, relNode -> true, description);
|
||||
}
|
||||
|
||||
<R extends RelNode> SolrConverterRule(Class<R> clazz, Predicate<RelNode> predicate, String description) {
|
||||
super(clazz, Convention.NONE, SolrRel.CONVENTION, description);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule to convert a {@link LogicalFilter} to a {@link SolrFilter}.
|
||||
*/
|
||||
private static class SolrFilterRule extends SolrConverterRule {
|
||||
private static boolean isNotFilterByExpr(List<RexNode> rexNodes, List<String> fieldNames) {
|
||||
|
||||
// We dont have a way to filter by result of aggregator now
|
||||
boolean result = true;
|
||||
|
||||
for (RexNode rexNode : rexNodes) {
|
||||
if (rexNode instanceof RexCall) {
|
||||
result = result && isNotFilterByExpr(((RexCall) rexNode).getOperands(), fieldNames);
|
||||
} else if (rexNode instanceof RexInputRef) {
|
||||
result = result && !fieldNames.get(((RexInputRef) rexNode).getIndex()).startsWith("EXPR$");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final Predicate<RelNode> FILTER_PREDICATE = relNode -> {
|
||||
List<RexNode> filterOperands = ((RexCall) ((LogicalFilter) relNode).getCondition()).getOperands();
|
||||
return isNotFilterByExpr(filterOperands, SolrRules.solrFieldNames(relNode.getRowType()));
|
||||
};
|
||||
|
||||
private static final SolrFilterRule FILTER_RULE = new SolrFilterRule();
|
||||
|
||||
private SolrFilterRule() {
|
||||
super(LogicalFilter.class, FILTER_PREDICATE, "SolrFilterRule");
|
||||
}
|
||||
|
||||
public RelNode convert(RelNode rel) {
|
||||
final LogicalFilter filter = (LogicalFilter) rel;
|
||||
final RelTraitSet traitSet = filter.getTraitSet().replace(out);
|
||||
return new SolrFilter(
|
||||
rel.getCluster(),
|
||||
traitSet,
|
||||
convert(filter.getInput(), out),
|
||||
filter.getCondition());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule to convert a {@link LogicalProject} to a {@link SolrProject}.
|
||||
*/
|
||||
private static class SolrProjectRule extends SolrConverterRule {
|
||||
private static final SolrProjectRule PROJECT_RULE = new SolrProjectRule();
|
||||
|
||||
private SolrProjectRule() {
|
||||
super(LogicalProject.class, "SolrProjectRule");
|
||||
}
|
||||
|
||||
public RelNode convert(RelNode rel) {
|
||||
final LogicalProject project = (LogicalProject) rel;
|
||||
final RelNode converted = convert(project.getInput(), out);
|
||||
final RelTraitSet traitSet = project.getTraitSet().replace(out);
|
||||
return new SolrProject(
|
||||
rel.getCluster(),
|
||||
traitSet,
|
||||
converted,
|
||||
project.getProjects(),
|
||||
project.getRowType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule to convert a {@link LogicalSort} to a {@link SolrSort}.
|
||||
*/
|
||||
private static class SolrSortRule extends SolrConverterRule {
|
||||
static final SolrSortRule SORT_RULE = new SolrSortRule(LogicalSort.class, "SolrSortRule");
|
||||
|
||||
SolrSortRule(Class<? extends RelNode> clazz, String description) {
|
||||
super(clazz, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelNode convert(RelNode rel) {
|
||||
final Sort sort = (Sort) rel;
|
||||
final RelTraitSet traitSet = sort.getTraitSet().replace(out).replace(sort.getCollation());
|
||||
return new SolrSort(
|
||||
rel.getCluster(),
|
||||
traitSet,
|
||||
convert(sort.getInput(), traitSet.replace(RelCollations.EMPTY)),
|
||||
sort.getCollation(),
|
||||
sort.offset,
|
||||
sort.fetch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule to convert an {@link LogicalAggregate} to an {@link SolrAggregate}.
|
||||
*/
|
||||
private static class SolrAggregateRule extends SolrConverterRule {
|
||||
// private static final Predicate<RelNode> AGGREGATE_PREDICTE = relNode ->
|
||||
// Aggregate.IS_SIMPLE.apply(((LogicalAggregate)relNode));// &&
|
||||
// !((LogicalAggregate)relNode).containsDistinctCall();
|
||||
|
||||
private static final RelOptRule AGGREGATE_RULE = new SolrAggregateRule();
|
||||
|
||||
private SolrAggregateRule() {
|
||||
super(LogicalAggregate.class, "SolrAggregateRule");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelNode convert(RelNode rel) {
|
||||
final LogicalAggregate agg = (LogicalAggregate) rel;
|
||||
final RelTraitSet traitSet = agg.getTraitSet().replace(out);
|
||||
return new SolrAggregate(
|
||||
rel.getCluster(),
|
||||
traitSet,
|
||||
convert(agg.getInput(), traitSet.simplify()),
|
||||
agg.indicator,
|
||||
agg.getGroupSet(),
|
||||
agg.getGroupSets(),
|
||||
agg.getAggCallList());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.apache.calcite.rel.type.*;
|
||||
import org.apache.calcite.schema.Table;
|
||||
import org.apache.calcite.schema.impl.AbstractSchema;
|
||||
import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
|
||||
import org.apache.solr.client.solrj.SolrServerException;
|
||||
import org.apache.solr.client.solrj.impl.CloudSolrClient;
|
||||
import org.apache.solr.client.solrj.request.LukeRequest;
|
||||
import org.apache.solr.client.solrj.response.LukeResponse;
|
||||
import org.apache.solr.common.cloud.Aliases;
|
||||
import org.apache.solr.common.cloud.ClusterState;
|
||||
import org.apache.solr.common.cloud.ZkStateReader;
|
||||
import org.apache.solr.common.luke.FieldFlag;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
class SolrSchema extends AbstractSchema {
|
||||
final Properties properties;
|
||||
|
||||
SolrSchema(Properties properties) {
|
||||
super();
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Table> getTableMap() {
|
||||
String zk = this.properties.getProperty("zk");
|
||||
try(CloudSolrClient cloudSolrClient = new CloudSolrClient.Builder().withZkHost(zk).build()) {
|
||||
cloudSolrClient.connect();
|
||||
ZkStateReader zkStateReader = cloudSolrClient.getZkStateReader();
|
||||
ClusterState clusterState = zkStateReader.getClusterState();
|
||||
|
||||
final ImmutableMap.Builder<String, Table> builder = ImmutableMap.builder();
|
||||
|
||||
for (String collection : clusterState.getCollectionsMap().keySet()) {
|
||||
builder.put(collection, new SolrTable(this, collection));
|
||||
}
|
||||
|
||||
Aliases aliases = zkStateReader.getAliases();
|
||||
if(aliases.collectionAliasSize() > 0) {
|
||||
for (Map.Entry<String, String> alias : aliases.getCollectionAliasMap().entrySet()) {
|
||||
builder.put(alias.getKey(), new SolrTable(this, alias.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, LukeResponse.FieldInfo> getFieldInfo(String collection) {
|
||||
String zk = this.properties.getProperty("zk");
|
||||
try(CloudSolrClient cloudSolrClient = new CloudSolrClient.Builder().withZkHost(zk).build()) {
|
||||
cloudSolrClient.connect();
|
||||
LukeRequest lukeRequest = new LukeRequest();
|
||||
lukeRequest.setNumTerms(0);
|
||||
LukeResponse lukeResponse = lukeRequest.process(cloudSolrClient, collection);
|
||||
return lukeResponse.getFieldInfo();
|
||||
} catch (SolrServerException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
RelProtoDataType getRelDataType(String collection) {
|
||||
// Temporary type factory, just for the duration of this method. Allowable
|
||||
// because we're creating a proto-type, not a type; before being used, the
|
||||
// proto-type will be copied into a real type factory.
|
||||
final RelDataTypeFactory typeFactory = new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
|
||||
final RelDataTypeFactory.FieldInfoBuilder fieldInfo = typeFactory.builder();
|
||||
Map<String, LukeResponse.FieldInfo> luceneFieldInfoMap = getFieldInfo(collection);
|
||||
|
||||
for(Map.Entry<String, LukeResponse.FieldInfo> entry : luceneFieldInfoMap.entrySet()) {
|
||||
LukeResponse.FieldInfo luceneFieldInfo = entry.getValue();
|
||||
|
||||
RelDataType type;
|
||||
switch (luceneFieldInfo.getType()) {
|
||||
case "string":
|
||||
type = typeFactory.createJavaType(String.class);
|
||||
break;
|
||||
case "int":
|
||||
case "long":
|
||||
type = typeFactory.createJavaType(Long.class);
|
||||
break;
|
||||
case "float":
|
||||
case "double":
|
||||
type = typeFactory.createJavaType(Double.class);
|
||||
break;
|
||||
default:
|
||||
type = typeFactory.createJavaType(String.class);
|
||||
}
|
||||
|
||||
EnumSet<FieldFlag> flags = luceneFieldInfo.parseFlags(luceneFieldInfo.getSchema());
|
||||
/*
|
||||
if(flags != null && flags.contains(FieldFlag.MULTI_VALUED)) {
|
||||
type = typeFactory.createArrayType(type, -1);
|
||||
}
|
||||
*/
|
||||
|
||||
fieldInfo.add(entry.getKey(), type).nullable(true);
|
||||
}
|
||||
fieldInfo.add("_query_",typeFactory.createJavaType(String.class));
|
||||
fieldInfo.add("score",typeFactory.createJavaType(Double.class));
|
||||
|
||||
return RelDataTypeImpl.proto(fieldInfo.build());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.plan.RelOptCluster;
|
||||
import org.apache.calcite.plan.RelOptCost;
|
||||
import org.apache.calcite.plan.RelOptPlanner;
|
||||
import org.apache.calcite.plan.RelTraitSet;
|
||||
import org.apache.calcite.rel.RelCollation;
|
||||
import org.apache.calcite.rel.RelFieldCollation;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.core.Sort;
|
||||
import org.apache.calcite.rel.metadata.RelMetadataQuery;
|
||||
import org.apache.calcite.rel.type.RelDataTypeField;
|
||||
import org.apache.calcite.rex.RexLiteral;
|
||||
import org.apache.calcite.rex.RexNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of {@link org.apache.calcite.rel.core.Sort} relational expression in Solr.
|
||||
*/
|
||||
class SolrSort extends Sort implements SolrRel {
|
||||
|
||||
SolrSort(RelOptCluster cluster, RelTraitSet traitSet, RelNode child, RelCollation collation, RexNode offset,
|
||||
RexNode fetch) {
|
||||
super(cluster, traitSet, child, collation, offset, fetch);
|
||||
|
||||
assert getConvention() == SolrRel.CONVENTION;
|
||||
assert getConvention() == child.getConvention();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
|
||||
return planner.getCostFactory().makeZeroCost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sort copy(RelTraitSet traitSet, RelNode input, RelCollation newCollation, RexNode offset, RexNode fetch) {
|
||||
return new SolrSort(getCluster(), traitSet, input, collation, offset, fetch);
|
||||
}
|
||||
|
||||
public void implement(Implementor implementor) {
|
||||
implementor.visitChild(0, getInput());
|
||||
|
||||
List<RelFieldCollation> sortCollations = collation.getFieldCollations();
|
||||
if (!sortCollations.isEmpty()) {
|
||||
// Construct a series of order clauses from the desired collation
|
||||
final List<RelDataTypeField> fields = getRowType().getFieldList();
|
||||
for (RelFieldCollation fieldCollation : sortCollations) {
|
||||
final String name = fields.get(fieldCollation.getFieldIndex()).getName();
|
||||
String direction = "asc";
|
||||
if (fieldCollation.getDirection().equals(RelFieldCollation.Direction.DESCENDING)) {
|
||||
direction = "desc";
|
||||
}
|
||||
implementor.addOrder(name, direction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(fetch != null) {
|
||||
implementor.setLimit(((RexLiteral) fetch).getValue().toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,842 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.adapter.java.AbstractQueryableTable;
|
||||
import org.apache.calcite.linq4j.*;
|
||||
import org.apache.calcite.plan.RelOptCluster;
|
||||
import org.apache.calcite.plan.RelOptTable;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.type.RelDataType;
|
||||
import org.apache.calcite.rel.type.RelDataTypeFactory;
|
||||
import org.apache.calcite.rel.type.RelProtoDataType;
|
||||
import org.apache.calcite.schema.SchemaPlus;
|
||||
import org.apache.calcite.schema.TranslatableTable;
|
||||
import org.apache.calcite.schema.impl.AbstractTableQueryable;
|
||||
import org.apache.calcite.util.Pair;
|
||||
import org.apache.solr.client.solrj.io.comp.ComparatorOrder;
|
||||
import org.apache.solr.client.solrj.io.comp.FieldComparator;
|
||||
import org.apache.solr.client.solrj.io.comp.MultipleFieldComparator;
|
||||
import org.apache.solr.client.solrj.io.comp.StreamComparator;
|
||||
import org.apache.solr.client.solrj.io.eq.FieldEqualitor;
|
||||
import org.apache.solr.client.solrj.io.eq.MultipleFieldEqualitor;
|
||||
import org.apache.solr.client.solrj.io.eq.StreamEqualitor;
|
||||
import org.apache.solr.client.solrj.io.ops.AndOperation;
|
||||
import org.apache.solr.client.solrj.io.ops.BooleanOperation;
|
||||
import org.apache.solr.client.solrj.io.ops.EqualsOperation;
|
||||
import org.apache.solr.client.solrj.io.ops.GreaterThanEqualToOperation;
|
||||
import org.apache.solr.client.solrj.io.ops.GreaterThanOperation;
|
||||
import org.apache.solr.client.solrj.io.ops.LessThanEqualToOperation;
|
||||
import org.apache.solr.client.solrj.io.ops.LessThanOperation;
|
||||
import org.apache.solr.client.solrj.io.ops.NotOperation;
|
||||
import org.apache.solr.client.solrj.io.ops.OrOperation;
|
||||
import org.apache.solr.client.solrj.io.stream.*;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.StreamExpressionParser;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
|
||||
import org.apache.solr.client.solrj.io.stream.metrics.*;
|
||||
import org.apache.solr.common.params.CommonParams;
|
||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Table based on a Solr collection
|
||||
*/
|
||||
class SolrTable extends AbstractQueryableTable implements TranslatableTable {
|
||||
private static final String DEFAULT_QUERY = "*:*";
|
||||
private static final String DEFAULT_VERSION_FIELD = "_version_";
|
||||
|
||||
private final String collection;
|
||||
private final SolrSchema schema;
|
||||
private RelProtoDataType protoRowType;
|
||||
|
||||
SolrTable(SolrSchema schema, String collection) {
|
||||
super(Object[].class);
|
||||
this.schema = schema;
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "SolrTable {" + collection + "}";
|
||||
}
|
||||
|
||||
public RelDataType getRowType(RelDataTypeFactory typeFactory) {
|
||||
if (protoRowType == null) {
|
||||
protoRowType = schema.getRelDataType(collection);
|
||||
}
|
||||
return protoRowType.apply(typeFactory);
|
||||
}
|
||||
|
||||
private Enumerable<Object> query(final Properties properties) {
|
||||
return query(properties, Collections.emptyList(), null, Collections.emptyList(), Collections.emptyList(),
|
||||
Collections.emptyList(), null, null, null);
|
||||
}
|
||||
|
||||
/** Executes a Solr query on the underlying table.
|
||||
*
|
||||
* @param properties Connections properties
|
||||
* @param fields List of fields to project
|
||||
* @param query A string for the query
|
||||
* @return Enumerator of results
|
||||
*/
|
||||
private Enumerable<Object> query(final Properties properties,
|
||||
final List<Map.Entry<String, Class>> fields,
|
||||
final String query,
|
||||
final List<Pair<String, String>> orders,
|
||||
final List<String> buckets,
|
||||
final List<Pair<String, String>> metricPairs,
|
||||
final String limit,
|
||||
final String negativeQuery,
|
||||
final String havingPredicate) {
|
||||
// SolrParams should be a ModifiableParams instead of a map
|
||||
boolean mapReduce = "map_reduce".equals(properties.getProperty("aggregationMode"));
|
||||
boolean negative = Boolean.parseBoolean(negativeQuery);
|
||||
|
||||
String q = null;
|
||||
|
||||
if (query == null) {
|
||||
q = DEFAULT_QUERY;
|
||||
} else {
|
||||
if(negative) {
|
||||
q = DEFAULT_QUERY + " AND " + query;
|
||||
} else {
|
||||
q = query;
|
||||
}
|
||||
}
|
||||
|
||||
TupleStream tupleStream;
|
||||
String zk = properties.getProperty("zk");
|
||||
try {
|
||||
if (metricPairs.isEmpty() && buckets.isEmpty()) {
|
||||
tupleStream = handleSelect(zk, collection, q, fields, orders, limit);
|
||||
} else {
|
||||
if(buckets.isEmpty()) {
|
||||
tupleStream = handleStats(zk, collection, q, metricPairs);
|
||||
} else {
|
||||
if(mapReduce) {
|
||||
tupleStream = handleGroupByMapReduce(zk,
|
||||
collection,
|
||||
properties,
|
||||
fields,
|
||||
q,
|
||||
orders,
|
||||
buckets,
|
||||
metricPairs,
|
||||
limit,
|
||||
havingPredicate);
|
||||
} else {
|
||||
tupleStream = handleGroupByFacet(zk,
|
||||
collection,
|
||||
fields,
|
||||
q,
|
||||
orders,
|
||||
buckets,
|
||||
metricPairs,
|
||||
limit,
|
||||
havingPredicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
final TupleStream finalStream = tupleStream;
|
||||
|
||||
return new AbstractEnumerable<Object>() {
|
||||
// Use original fields list to make sure only the fields specified are enumerated
|
||||
public Enumerator<Object> enumerator() {
|
||||
return new SolrEnumerator(finalStream, fields);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static StreamComparator bucketSortComp(List<Bucket> buckets, Map<String,String> dirs) {
|
||||
FieldComparator[] comps = new FieldComparator[buckets.size()];
|
||||
for(int i=0; i<buckets.size(); i++) {
|
||||
ComparatorOrder comparatorOrder = ComparatorOrder.fromString(dirs.get(buckets.get(i).toString()));
|
||||
String sortKey = buckets.get(i).toString();
|
||||
comps[i] = new FieldComparator(sortKey, comparatorOrder);
|
||||
}
|
||||
|
||||
if(comps.length == 1) {
|
||||
return comps[0];
|
||||
} else {
|
||||
return new MultipleFieldComparator(comps);
|
||||
}
|
||||
}
|
||||
|
||||
private static StreamComparator bucketSortComp(Bucket[] buckets, String dir) {
|
||||
FieldComparator[] comps = new FieldComparator[buckets.length];
|
||||
for(int i=0; i<buckets.length; i++) {
|
||||
ComparatorOrder comparatorOrder = ascDescComp(dir);
|
||||
String sortKey = buckets[i].toString();
|
||||
comps[i] = new FieldComparator(sortKey, comparatorOrder);
|
||||
}
|
||||
|
||||
if(comps.length == 1) {
|
||||
return comps[0];
|
||||
} else {
|
||||
return new MultipleFieldComparator(comps);
|
||||
}
|
||||
}
|
||||
|
||||
private String getSortDirection(Map.Entry<String, String> order) {
|
||||
String direction = order.getValue();
|
||||
return direction == null ? "asc" : direction;
|
||||
}
|
||||
|
||||
private StreamComparator getComp(List<? extends Map.Entry<String, String>> orders) {
|
||||
FieldComparator[] comps = new FieldComparator[orders.size()];
|
||||
for(int i = 0; i < orders.size(); i++) {
|
||||
Map.Entry<String, String> order = orders.get(i);
|
||||
String direction = getSortDirection(order);
|
||||
ComparatorOrder comparatorOrder = ComparatorOrder.fromString(direction);
|
||||
String sortKey = order.getKey();
|
||||
comps[i] = new FieldComparator(sortKey, comparatorOrder);
|
||||
}
|
||||
|
||||
if(comps.length == 1) {
|
||||
return comps[0];
|
||||
} else {
|
||||
return new MultipleFieldComparator(comps);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Metric> buildMetrics(List<Pair<String, String>> metricPairs, boolean ifEmptyCount) {
|
||||
List<Metric> metrics = new ArrayList<>(metricPairs.size());
|
||||
metrics.addAll(metricPairs.stream().map(this::getMetric).collect(Collectors.toList()));
|
||||
if(metrics.size() == 0 && ifEmptyCount) {
|
||||
metrics.add(new CountMetric());
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
private Metric getMetric(Pair<String, String> metricPair) {
|
||||
switch (metricPair.getKey()) {
|
||||
case "COUNT":
|
||||
return new CountMetric(metricPair.getValue());
|
||||
case "SUM":
|
||||
case "$SUM0":
|
||||
return new SumMetric(metricPair.getValue());
|
||||
case "MIN":
|
||||
return new MinMetric(metricPair.getValue());
|
||||
case "MAX":
|
||||
return new MaxMetric(metricPair.getValue());
|
||||
case "AVG":
|
||||
return new MeanMetric(metricPair.getValue());
|
||||
default:
|
||||
throw new IllegalArgumentException(metricPair.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
private TupleStream handleSelect(String zk,
|
||||
String collection,
|
||||
String query,
|
||||
List<Map.Entry<String, Class>> fields,
|
||||
List<Pair<String, String>> orders,
|
||||
String limit) throws IOException {
|
||||
|
||||
ModifiableSolrParams params = new ModifiableSolrParams();
|
||||
params.add(CommonParams.Q, query);
|
||||
|
||||
//Validate the fields
|
||||
for(Map.Entry<String, Class> entry : fields) {
|
||||
String fname = entry.getKey();
|
||||
if(limit == null && "score".equals(fname)) {
|
||||
throw new IOException("score is not a valid field for unlimited queries.");
|
||||
}
|
||||
|
||||
if(fname.contains("*")) {
|
||||
throw new IOException("* is not supported for column selection.");
|
||||
}
|
||||
}
|
||||
|
||||
String fl = getFields(fields);
|
||||
|
||||
if(orders.size() > 0) {
|
||||
params.add(CommonParams.SORT, getSort(orders));
|
||||
} else {
|
||||
if(limit == null) {
|
||||
params.add(CommonParams.SORT, "_version_ desc");
|
||||
fl = fl+",_version_";
|
||||
} else {
|
||||
params.add(CommonParams.SORT, "score desc");
|
||||
if(fl.indexOf("score") == -1) {
|
||||
fl = fl + ",score";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.add(CommonParams.FL, fl);
|
||||
|
||||
if (limit != null) {
|
||||
params.add(CommonParams.ROWS, limit);
|
||||
return new LimitStream(new CloudSolrStream(zk, collection, params), Integer.parseInt(limit));
|
||||
} else {
|
||||
params.add(CommonParams.QT, "/export");
|
||||
return new CloudSolrStream(zk, collection, params);
|
||||
}
|
||||
}
|
||||
|
||||
private String getSort(List<Pair<String, String>> orders) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for(Pair<String, String> pair : orders) {
|
||||
if(buf.length() > 0) {
|
||||
buf.append(",");
|
||||
}
|
||||
buf.append(pair.getKey()).append(" ").append(pair.getValue());
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String getSingleSort(Pair<String, String> order) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(order.getKey()).append(" ").append(order.getValue());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String getFields(List<Map.Entry<String, Class>> fields) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for(Map.Entry<String, Class> field : fields) {
|
||||
|
||||
if(buf.length() > 0) {
|
||||
buf.append(",");
|
||||
}
|
||||
|
||||
buf.append(field.getKey());
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String getFields(Set<String> fieldSet) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
boolean appendVersion = true;
|
||||
for(String field : fieldSet) {
|
||||
|
||||
if(buf.length() > 0) {
|
||||
buf.append(",");
|
||||
}
|
||||
|
||||
if(field.equals("_version_")) {
|
||||
appendVersion = false;
|
||||
}
|
||||
|
||||
buf.append(field);
|
||||
}
|
||||
|
||||
if(appendVersion){
|
||||
buf.append(",_version_");
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
private Set<String> getFieldSet(Metric[] metrics, List<Map.Entry<String, Class>> fields) {
|
||||
HashSet set = new HashSet();
|
||||
for(Metric metric : metrics) {
|
||||
for(String column : metric.getColumns()) {
|
||||
set.add(column);
|
||||
}
|
||||
}
|
||||
|
||||
for(Map.Entry<String, Class> field : fields) {
|
||||
if(field.getKey().indexOf('(') == -1) {
|
||||
set.add(field.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
private static String getSortDirection(List<Pair<String, String>> orders) {
|
||||
if(orders != null && orders.size() > 0) {
|
||||
for(Pair<String,String> item : orders) {
|
||||
return item.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return "asc";
|
||||
}
|
||||
|
||||
private static String bucketSort(Bucket[] buckets, String dir) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
boolean comma = false;
|
||||
for(Bucket bucket : buckets) {
|
||||
if(comma) {
|
||||
buf.append(",");
|
||||
}
|
||||
buf.append(bucket.toString()).append(" ").append(dir);
|
||||
comma = true;
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static String getPartitionKeys(Bucket[] buckets) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
boolean comma = false;
|
||||
for(Bucket bucket : buckets) {
|
||||
if(comma) {
|
||||
buf.append(",");
|
||||
}
|
||||
buf.append(bucket.toString());
|
||||
comma = true;
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static boolean sortsEqual(Bucket[] buckets, String direction, List<Pair<String, String>> orders) {
|
||||
|
||||
if(buckets.length != orders.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i=0; i< buckets.length; i++) {
|
||||
Bucket bucket = buckets[i];
|
||||
Pair<String, String> order = orders.get(i);
|
||||
if(!bucket.toString().equals(order.getKey())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!order.getValue().toLowerCase(Locale.ROOT).contains(direction.toLowerCase(Locale.ROOT))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private TupleStream handleGroupByMapReduce(String zk,
|
||||
String collection,
|
||||
Properties properties,
|
||||
final List<Map.Entry<String, Class>> fields,
|
||||
final String query,
|
||||
final List<Pair<String, String>> orders,
|
||||
final List<String> _buckets,
|
||||
final List<Pair<String, String>> metricPairs,
|
||||
final String limit,
|
||||
final String havingPredicate) throws IOException {
|
||||
|
||||
int numWorkers = Integer.parseInt(properties.getProperty("numWorkers", "1"));
|
||||
|
||||
Bucket[] buckets = buildBuckets(_buckets, fields);
|
||||
Metric[] metrics = buildMetrics(metricPairs, false).toArray(new Metric[0]);
|
||||
|
||||
if(metrics.length == 0) {
|
||||
return handleSelectDistinctMapReduce(zk, collection, properties, fields, query, orders, buckets, limit);
|
||||
}
|
||||
|
||||
Set<String> fieldSet = getFieldSet(metrics, fields);
|
||||
|
||||
if(metrics.length == 0) {
|
||||
throw new IOException("Group by queries must include atleast one aggregate function.");
|
||||
}
|
||||
|
||||
String fl = getFields(fieldSet);
|
||||
String sortDirection = getSortDirection(orders);
|
||||
String sort = bucketSort(buckets, sortDirection);
|
||||
|
||||
ModifiableSolrParams params = new ModifiableSolrParams();
|
||||
|
||||
params.set(CommonParams.FL, fl);
|
||||
params.set(CommonParams.Q, query);
|
||||
//Always use the /export handler for Group By Queries because it requires exporting full result sets.
|
||||
params.set(CommonParams.QT, "/export");
|
||||
|
||||
if(numWorkers > 1) {
|
||||
params.set("partitionKeys", getPartitionKeys(buckets));
|
||||
}
|
||||
|
||||
params.set("sort", sort);
|
||||
|
||||
TupleStream tupleStream = null;
|
||||
|
||||
CloudSolrStream cstream = new CloudSolrStream(zk, collection, params);
|
||||
tupleStream = new RollupStream(cstream, buckets, metrics);
|
||||
|
||||
StreamFactory factory = new StreamFactory()
|
||||
.withFunctionName("search", CloudSolrStream.class)
|
||||
.withFunctionName("parallel", ParallelStream.class)
|
||||
.withFunctionName("rollup", RollupStream.class)
|
||||
.withFunctionName("sum", SumMetric.class)
|
||||
.withFunctionName("min", MinMetric.class)
|
||||
.withFunctionName("max", MaxMetric.class)
|
||||
.withFunctionName("avg", MeanMetric.class)
|
||||
.withFunctionName("count", CountMetric.class)
|
||||
.withFunctionName("and", AndOperation.class)
|
||||
.withFunctionName("or", OrOperation.class)
|
||||
.withFunctionName("not", NotOperation.class)
|
||||
.withFunctionName("eq", EqualsOperation.class)
|
||||
.withFunctionName("gt", GreaterThanOperation.class)
|
||||
.withFunctionName("lt", LessThanOperation.class)
|
||||
.withFunctionName("lteq", LessThanEqualToOperation.class)
|
||||
.withFunctionName("having", HavingStream.class)
|
||||
.withFunctionName("gteq", GreaterThanEqualToOperation.class);
|
||||
|
||||
if(havingPredicate != null) {
|
||||
BooleanOperation booleanOperation = (BooleanOperation)factory.constructOperation(StreamExpressionParser.parse(havingPredicate));
|
||||
tupleStream = new HavingStream(tupleStream, booleanOperation);
|
||||
}
|
||||
|
||||
if(numWorkers > 1) {
|
||||
// Do the rollups in parallel
|
||||
// Maintain the sort of the Tuples coming from the workers.
|
||||
StreamComparator comp = bucketSortComp(buckets, sortDirection);
|
||||
ParallelStream parallelStream = new ParallelStream(zk, collection, tupleStream, numWorkers, comp);
|
||||
|
||||
|
||||
parallelStream.setStreamFactory(factory);
|
||||
tupleStream = parallelStream;
|
||||
}
|
||||
|
||||
//TODO: Currently we are not pushing down the having clause.
|
||||
// We need to push down the having clause to ensure that LIMIT does not cut off records prior to the having filter.
|
||||
|
||||
if(orders != null && orders.size() > 0) {
|
||||
if(!sortsEqual(buckets, sortDirection, orders)) {
|
||||
int lim = (limit == null) ? 100 : Integer.parseInt(limit);
|
||||
StreamComparator comp = getComp(orders);
|
||||
//Rank the Tuples
|
||||
//If parallel stream is used ALL the Rolled up tuples from the workers will be ranked
|
||||
//Providing a true Top or Bottom.
|
||||
tupleStream = new RankStream(tupleStream, lim, comp);
|
||||
} else {
|
||||
// Sort is the same as the same as the underlying stream
|
||||
// Only need to limit the result, not Rank the result
|
||||
if(limit != null) {
|
||||
tupleStream = new LimitStream(tupleStream, Integer.parseInt(limit));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//No order by, check for limit
|
||||
if(limit != null) {
|
||||
tupleStream = new LimitStream(tupleStream, Integer.parseInt(limit));
|
||||
}
|
||||
}
|
||||
|
||||
return tupleStream;
|
||||
}
|
||||
|
||||
private Bucket[] buildBuckets(List<String> buckets, List<Map.Entry<String, Class>> fields) {
|
||||
Bucket[] bucketsArray = new Bucket[buckets.size()];
|
||||
|
||||
int i=0;
|
||||
for(Map.Entry<String,Class> field : fields) {
|
||||
String fieldName = field.getKey();
|
||||
if(buckets.contains(fieldName)) {
|
||||
bucketsArray[i++] = new Bucket(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
return bucketsArray;
|
||||
}
|
||||
|
||||
private TupleStream handleGroupByFacet(String zkHost,
|
||||
String collection,
|
||||
final List<Map.Entry<String, Class>> fields,
|
||||
final String query,
|
||||
final List<Pair<String, String>> orders,
|
||||
final List<String> bucketFields,
|
||||
final List<Pair<String, String>> metricPairs,
|
||||
final String lim,
|
||||
final String havingPredicate) throws IOException {
|
||||
|
||||
ModifiableSolrParams solrParams = new ModifiableSolrParams();
|
||||
solrParams.add(CommonParams.Q, query);
|
||||
|
||||
Bucket[] buckets = buildBuckets(bucketFields, fields);
|
||||
Metric[] metrics = buildMetrics(metricPairs, true).toArray(new Metric[0]);
|
||||
if(metrics.length == 0) {
|
||||
metrics = new Metric[1];
|
||||
metrics[0] = new CountMetric();
|
||||
}
|
||||
|
||||
int limit = lim != null ? Integer.parseInt(lim) : 1000;
|
||||
|
||||
FieldComparator[] sorts = null;
|
||||
|
||||
if(orders == null || orders.size() == 0) {
|
||||
sorts = new FieldComparator[buckets.length];
|
||||
for(int i=0; i<sorts.length; i++) {
|
||||
sorts[i] = new FieldComparator("index", ComparatorOrder.ASCENDING);
|
||||
}
|
||||
} else {
|
||||
sorts = getComps(orders);
|
||||
}
|
||||
|
||||
int overfetch = (int)(limit * 1.25);
|
||||
|
||||
TupleStream tupleStream = new FacetStream(zkHost,
|
||||
collection,
|
||||
solrParams,
|
||||
buckets,
|
||||
metrics,
|
||||
sorts,
|
||||
overfetch);
|
||||
|
||||
|
||||
|
||||
StreamFactory factory = new StreamFactory()
|
||||
.withFunctionName("search", CloudSolrStream.class)
|
||||
.withFunctionName("parallel", ParallelStream.class)
|
||||
.withFunctionName("rollup", RollupStream.class)
|
||||
.withFunctionName("sum", SumMetric.class)
|
||||
.withFunctionName("min", MinMetric.class)
|
||||
.withFunctionName("max", MaxMetric.class)
|
||||
.withFunctionName("avg", MeanMetric.class)
|
||||
.withFunctionName("count", CountMetric.class)
|
||||
.withFunctionName("and", AndOperation.class)
|
||||
.withFunctionName("or", OrOperation.class)
|
||||
.withFunctionName("not", NotOperation.class)
|
||||
.withFunctionName("eq", EqualsOperation.class)
|
||||
.withFunctionName("gt", GreaterThanOperation.class)
|
||||
.withFunctionName("lt", LessThanOperation.class)
|
||||
.withFunctionName("lteq", LessThanEqualToOperation.class)
|
||||
.withFunctionName("gteq", GreaterThanEqualToOperation.class);
|
||||
|
||||
if(havingPredicate != null) {
|
||||
BooleanOperation booleanOperation = (BooleanOperation)factory.constructOperation(StreamExpressionParser.parse(havingPredicate));
|
||||
tupleStream = new HavingStream(tupleStream, booleanOperation);
|
||||
}
|
||||
|
||||
if(lim != null)
|
||||
{
|
||||
tupleStream = new LimitStream(tupleStream, limit);
|
||||
}
|
||||
|
||||
return tupleStream;
|
||||
}
|
||||
|
||||
private TupleStream handleSelectDistinctMapReduce(final String zkHost,
|
||||
final String collection,
|
||||
final Properties properties,
|
||||
final List<Map.Entry<String, Class>> fields,
|
||||
final String query,
|
||||
final List<Pair<String, String>> orders,
|
||||
final Bucket[] buckets,
|
||||
final String limit) throws IOException{
|
||||
|
||||
int numWorkers = Integer.parseInt(properties.getProperty("numWorkers", "1"));
|
||||
|
||||
String fl = getFields(fields);
|
||||
|
||||
String sort = null;
|
||||
StreamEqualitor ecomp = null;
|
||||
StreamComparator comp = null;
|
||||
|
||||
if(orders != null && orders.size() > 0) {
|
||||
StreamComparator[] adjustedSorts = adjustSorts(orders, buckets);
|
||||
// Because of the way adjustSorts works we know that each FieldComparator has a single
|
||||
// field name. For this reason we can just look at the leftFieldName
|
||||
FieldEqualitor[] fieldEqualitors = new FieldEqualitor[adjustedSorts.length];
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for(int i=0; i<adjustedSorts.length; i++) {
|
||||
FieldComparator fieldComparator = (FieldComparator)adjustedSorts[i];
|
||||
fieldEqualitors[i] = new FieldEqualitor(fieldComparator.getLeftFieldName());
|
||||
if(i>0) {
|
||||
buf.append(",");
|
||||
}
|
||||
buf.append(fieldComparator.getLeftFieldName()).append(" ").append(fieldComparator.getOrder().toString());
|
||||
}
|
||||
|
||||
sort = buf.toString();
|
||||
|
||||
if(adjustedSorts.length == 1) {
|
||||
ecomp = fieldEqualitors[0];
|
||||
comp = adjustedSorts[0];
|
||||
} else {
|
||||
ecomp = new MultipleFieldEqualitor(fieldEqualitors);
|
||||
comp = new MultipleFieldComparator(adjustedSorts);
|
||||
}
|
||||
} else {
|
||||
StringBuilder sortBuf = new StringBuilder();
|
||||
FieldEqualitor[] equalitors = new FieldEqualitor[buckets.length];
|
||||
StreamComparator[] streamComparators = new StreamComparator[buckets.length];
|
||||
for(int i=0; i<buckets.length; i++) {
|
||||
equalitors[i] = new FieldEqualitor(buckets[i].toString());
|
||||
streamComparators[i] = new FieldComparator(buckets[i].toString(), ComparatorOrder.ASCENDING);
|
||||
if(i>0) {
|
||||
sortBuf.append(',');
|
||||
}
|
||||
sortBuf.append(buckets[i].toString()).append(" asc");
|
||||
}
|
||||
|
||||
sort = sortBuf.toString();
|
||||
|
||||
if(equalitors.length == 1) {
|
||||
ecomp = equalitors[0];
|
||||
comp = streamComparators[0];
|
||||
} else {
|
||||
ecomp = new MultipleFieldEqualitor(equalitors);
|
||||
comp = new MultipleFieldComparator(streamComparators);
|
||||
}
|
||||
}
|
||||
|
||||
ModifiableSolrParams params = new ModifiableSolrParams();
|
||||
|
||||
params.set(CommonParams.FL, fl);
|
||||
params.set(CommonParams.Q, query);
|
||||
//Always use the /export handler for Distinct Queries because it requires exporting full result sets.
|
||||
params.set(CommonParams.QT, "/export");
|
||||
|
||||
if(numWorkers > 1) {
|
||||
params.set("partitionKeys", getPartitionKeys(buckets));
|
||||
}
|
||||
|
||||
params.set("sort", sort);
|
||||
|
||||
TupleStream tupleStream = null;
|
||||
|
||||
CloudSolrStream cstream = new CloudSolrStream(zkHost, collection, params);
|
||||
tupleStream = new UniqueStream(cstream, ecomp);
|
||||
|
||||
if(numWorkers > 1) {
|
||||
// Do the unique in parallel
|
||||
// Maintain the sort of the Tuples coming from the workers.
|
||||
ParallelStream parallelStream = new ParallelStream(zkHost, collection, tupleStream, numWorkers, comp);
|
||||
|
||||
StreamFactory factory = new StreamFactory()
|
||||
.withFunctionName("search", CloudSolrStream.class)
|
||||
.withFunctionName("parallel", ParallelStream.class)
|
||||
.withFunctionName("unique", UniqueStream.class);
|
||||
|
||||
parallelStream.setStreamFactory(factory);
|
||||
tupleStream = parallelStream;
|
||||
}
|
||||
|
||||
if(limit != null) {
|
||||
tupleStream = new LimitStream(tupleStream, Integer.parseInt(limit));
|
||||
}
|
||||
|
||||
return tupleStream;
|
||||
}
|
||||
|
||||
|
||||
private StreamComparator[] adjustSorts(List<Pair<String, String>> orders, Bucket[] buckets) throws IOException {
|
||||
List<FieldComparator> adjustedSorts = new ArrayList();
|
||||
Set<String> bucketFields = new HashSet();
|
||||
Set<String> sortFields = new HashSet();
|
||||
|
||||
ComparatorOrder comparatorOrder = ComparatorOrder.ASCENDING;
|
||||
for(Pair<String, String> order : orders) {
|
||||
sortFields.add(order.getKey());
|
||||
adjustedSorts.add(new FieldComparator(order.getKey(), ascDescComp(order.getValue())));
|
||||
comparatorOrder = ascDescComp(order.getValue());
|
||||
}
|
||||
|
||||
for(Bucket bucket : buckets) {
|
||||
bucketFields.add(bucket.toString());
|
||||
}
|
||||
|
||||
for(String sf : sortFields) {
|
||||
if(!bucketFields.contains(sf)) {
|
||||
throw new IOException("All sort fields must be in the field list.");
|
||||
}
|
||||
}
|
||||
|
||||
//Add sort fields if needed
|
||||
if(sortFields.size() < buckets.length) {
|
||||
for(Bucket bucket : buckets) {
|
||||
String b = bucket.toString();
|
||||
if(!sortFields.contains(b)) {
|
||||
adjustedSorts.add(new FieldComparator(bucket.toString(), comparatorOrder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return adjustedSorts.toArray(new FieldComparator[adjustedSorts.size()]);
|
||||
}
|
||||
|
||||
private TupleStream handleStats(String zk,
|
||||
String collection,
|
||||
String query,
|
||||
List<Pair<String, String>> metricPairs) {
|
||||
|
||||
|
||||
ModifiableSolrParams solrParams = new ModifiableSolrParams();
|
||||
solrParams.add(CommonParams.Q, query);
|
||||
Metric[] metrics = buildMetrics(metricPairs, false).toArray(new Metric[0]);
|
||||
return new StatsStream(zk, collection, solrParams, metrics);
|
||||
}
|
||||
|
||||
public <T> Queryable<T> asQueryable(QueryProvider queryProvider, SchemaPlus schema, String tableName) {
|
||||
return new SolrQueryable<>(queryProvider, schema, this, tableName);
|
||||
}
|
||||
|
||||
public RelNode toRel(RelOptTable.ToRelContext context, RelOptTable relOptTable) {
|
||||
final RelOptCluster cluster = context.getCluster();
|
||||
return new SolrTableScan(cluster, cluster.traitSetOf(SolrRel.CONVENTION), relOptTable, this, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static class SolrQueryable<T> extends AbstractTableQueryable<T> {
|
||||
SolrQueryable(QueryProvider queryProvider, SchemaPlus schema, SolrTable table, String tableName) {
|
||||
super(queryProvider, schema, table, tableName);
|
||||
}
|
||||
|
||||
public Enumerator<T> enumerator() {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Enumerable<T> enumerable = (Enumerable<T>) getTable().query(getProperties());
|
||||
return enumerable.enumerator();
|
||||
}
|
||||
|
||||
private SolrTable getTable() {
|
||||
return (SolrTable) table;
|
||||
}
|
||||
|
||||
private Properties getProperties() {
|
||||
return schema.unwrap(SolrSchema.class).properties;
|
||||
}
|
||||
|
||||
/** Called via code-generation.
|
||||
*
|
||||
* @see SolrMethod#SOLR_QUERYABLE_QUERY
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public Enumerable<Object> query(List<Map.Entry<String, Class>> fields, String query, List<Pair<String, String>> order,
|
||||
List<String> buckets, List<Pair<String, String>> metricPairs, String limit, String negativeQuery, String havingPredicate) {
|
||||
return getTable().query(getProperties(), fields, query, order, buckets, metricPairs, limit, negativeQuery, havingPredicate);
|
||||
}
|
||||
}
|
||||
|
||||
private static FieldComparator[] getComps(List<Pair<String, String>> orders) {
|
||||
FieldComparator[] comps = new FieldComparator[orders.size()];
|
||||
for(int i=0; i<orders.size(); i++) {
|
||||
Pair<String,String> sortItem = orders.get(i);
|
||||
String ordering = sortItem.getValue();
|
||||
ComparatorOrder comparatorOrder = ascDescComp(ordering);
|
||||
String sortKey = sortItem.getKey();
|
||||
comps[i] = new FieldComparator(sortKey, comparatorOrder);
|
||||
}
|
||||
|
||||
return comps;
|
||||
}
|
||||
|
||||
private static ComparatorOrder ascDescComp(String s) {
|
||||
if(s.toLowerCase(Locale.ROOT).contains("desc")) {
|
||||
return ComparatorOrder.DESCENDING;
|
||||
} else {
|
||||
return ComparatorOrder.ASCENDING;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.plan.*;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.core.TableScan;
|
||||
import org.apache.calcite.rel.metadata.RelMetadataQuery;
|
||||
import org.apache.calcite.rel.type.RelDataType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Relational expression representing a scan of a Solr collection.
|
||||
*/
|
||||
class SolrTableScan extends TableScan implements SolrRel {
|
||||
private final SolrTable solrTable;
|
||||
private final RelDataType projectRowType;
|
||||
|
||||
/**
|
||||
* Creates a SolrTableScan.
|
||||
*
|
||||
* @param cluster Cluster
|
||||
* @param traitSet Traits
|
||||
* @param table Table
|
||||
* @param solrTable Solr table
|
||||
* @param projectRowType Fields and types to project; null to project raw row
|
||||
*/
|
||||
SolrTableScan(RelOptCluster cluster, RelTraitSet traitSet, RelOptTable table, SolrTable solrTable,
|
||||
RelDataType projectRowType) {
|
||||
super(cluster, traitSet, table);
|
||||
this.solrTable = solrTable;
|
||||
this.projectRowType = projectRowType;
|
||||
|
||||
assert solrTable != null;
|
||||
assert getConvention() == SolrRel.CONVENTION;
|
||||
}
|
||||
|
||||
@Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
|
||||
final float f = projectRowType == null ? 1f : (float) projectRowType.getFieldCount() / 100f;
|
||||
return super.computeSelfCost(planner, mq).multiplyBy(.1 * f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
|
||||
assert inputs.isEmpty();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelDataType deriveRowType() {
|
||||
return projectRowType != null ? projectRowType : super.deriveRowType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RelOptPlanner planner) {
|
||||
planner.addRule(SolrToEnumerableConverterRule.INSTANCE);
|
||||
for (RelOptRule rule : SolrRules.RULES) {
|
||||
planner.addRule(rule);
|
||||
}
|
||||
}
|
||||
|
||||
public void implement(Implementor implementor) {
|
||||
implementor.solrTable = solrTable;
|
||||
implementor.table = table;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.calcite.adapter.enumerable.*;
|
||||
import org.apache.calcite.linq4j.tree.BlockBuilder;
|
||||
import org.apache.calcite.linq4j.tree.Expression;
|
||||
import org.apache.calcite.linq4j.tree.Expressions;
|
||||
import org.apache.calcite.linq4j.tree.MethodCallExpression;
|
||||
import org.apache.calcite.plan.*;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.convert.ConverterImpl;
|
||||
import org.apache.calcite.rel.metadata.RelMetadataQuery;
|
||||
import org.apache.calcite.rel.type.RelDataType;
|
||||
import org.apache.calcite.runtime.Hook;
|
||||
import org.apache.calcite.util.BuiltInMethod;
|
||||
import org.apache.calcite.util.Pair;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Relational expression representing a scan of a table in Solr
|
||||
*/
|
||||
class SolrToEnumerableConverter extends ConverterImpl implements EnumerableRel {
|
||||
SolrToEnumerableConverter(RelOptCluster cluster, RelTraitSet traits, RelNode input) {
|
||||
super(cluster, ConventionTraitDef.INSTANCE, traits, input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
|
||||
return new SolrToEnumerableConverter(getCluster(), traitSet, sole(inputs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
|
||||
return super.computeSelfCost(planner, mq).multiplyBy(.1);
|
||||
}
|
||||
|
||||
public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
|
||||
// Generates a call to "query" with the appropriate fields
|
||||
final BlockBuilder list = new BlockBuilder();
|
||||
final SolrRel.Implementor solrImplementor = new SolrRel.Implementor();
|
||||
solrImplementor.visitChild(0, getInput());
|
||||
final RelDataType rowType = getRowType();
|
||||
final PhysType physType = PhysTypeImpl.of(implementor.getTypeFactory(), rowType, pref.prefer(JavaRowFormat.ARRAY));
|
||||
final Expression table = list.append("table", solrImplementor.table.getExpression(SolrTable.SolrQueryable.class));
|
||||
final Expression fields =
|
||||
list.append("fields",
|
||||
constantArrayList(
|
||||
Pair.zip(generateFields(SolrRules.solrFieldNames(rowType), solrImplementor.fieldMappings),
|
||||
new AbstractList<Class>() {
|
||||
@Override
|
||||
public Class get(int index) {
|
||||
return physType.fieldClass(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rowType.getFieldCount();
|
||||
}
|
||||
}),
|
||||
Pair.class));
|
||||
final Expression query = list.append("query", Expressions.constant(solrImplementor.query, String.class));
|
||||
final Expression orders = list.append("orders", constantArrayList(solrImplementor.orders, Pair.class));
|
||||
final Expression buckets = list.append("buckets", constantArrayList(solrImplementor.buckets, String.class));
|
||||
final Expression metricPairs = list.append("metricPairs", constantArrayList(solrImplementor.metricPairs, Pair.class));
|
||||
final Expression limit = list.append("limit", Expressions.constant(solrImplementor.limitValue));
|
||||
final Expression negativeQuery = list.append("negativeQuery", Expressions.constant(Boolean.toString(solrImplementor.negativeQuery), String.class));
|
||||
final Expression havingPredicate = list.append("havingTest", Expressions.constant(solrImplementor.havingPredicate, String.class));
|
||||
Expression enumerable = list.append("enumerable", Expressions.call(table, SolrMethod.SOLR_QUERYABLE_QUERY.method,
|
||||
fields, query, orders, buckets, metricPairs, limit, negativeQuery, havingPredicate));
|
||||
Hook.QUERY_PLAN.run(query);
|
||||
list.add(Expressions.return_(null, enumerable));
|
||||
return implementor.result(physType, list.toBlock());
|
||||
}
|
||||
|
||||
private List<String> generateFields(List<String> queryFields, Map<String, String> fieldMappings) {
|
||||
if(fieldMappings.isEmpty()) {
|
||||
return queryFields;
|
||||
} else {
|
||||
List<String> fields = new ArrayList<>();
|
||||
for(String field : queryFields) {
|
||||
fields.add(getField(fieldMappings, field));
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
||||
private String getField(Map<String, String> fieldMappings, String field) {
|
||||
String retField = field;
|
||||
while(fieldMappings.containsKey(field)) {
|
||||
field = fieldMappings.getOrDefault(field, retField);
|
||||
if(retField.equals(field)) {
|
||||
break;
|
||||
} else {
|
||||
retField = field;
|
||||
}
|
||||
}
|
||||
return retField;
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g. {@code constantArrayList("x", "y")} returns
|
||||
* "Arrays.asList('x', 'y')".
|
||||
*/
|
||||
private static <T> MethodCallExpression constantArrayList(List<T> values, Class clazz) {
|
||||
return Expressions.call(BuiltInMethod.ARRAYS_AS_LIST.method,
|
||||
Expressions.newArrayInit(clazz, constantList(values)));
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g. {@code constantList("x", "y")} returns "{ConstantExpression("x"), ConstantExpression("y")}".
|
||||
*/
|
||||
private static <T> List<Expression> constantList(List<T> values) {
|
||||
return Lists.transform(values, Expressions::constant);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
||||
|
||||
import org.apache.calcite.adapter.enumerable.EnumerableConvention;
|
||||
import org.apache.calcite.plan.RelTraitSet;
|
||||
import org.apache.calcite.rel.RelNode;
|
||||
import org.apache.calcite.rel.convert.ConverterRule;
|
||||
|
||||
/**
|
||||
* Rule to convert a relational expression from {@link SolrRel#CONVENTION} to {@link EnumerableConvention}.
|
||||
*/
|
||||
class SolrToEnumerableConverterRule extends ConverterRule {
|
||||
static final ConverterRule INSTANCE = new SolrToEnumerableConverterRule();
|
||||
|
||||
private SolrToEnumerableConverterRule() {
|
||||
super(RelNode.class, SolrRel.CONVENTION, EnumerableConvention.INSTANCE, "SolrToEnumerableConverterRule");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelNode convert(RelNode rel) {
|
||||
RelTraitSet newTraitSet = rel.getTraitSet().replace(getOutConvention());
|
||||
return new SolrToEnumerableConverter(rel.getCluster(), newTraitSet, rel);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes related to Apache Calcite implementation in {@link org.apache.solr.handler.SQLHandler}
|
||||
*/
|
||||
package org.apache.solr.handler.sql;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
c16b346eef02495f2f4b429fe04c33e526ec0229
|
|
@ -0,0 +1,268 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
APACHE CALCITE SUBCOMPONENTS:
|
||||
|
||||
The Apache Calcite project contains subcomponents with separate copyright
|
||||
notices and license terms. Your use of the source code for the these
|
||||
subcomponents is subject to the terms and conditions of the following
|
||||
licenses.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
The MIT License
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
The Apache Calcite project bundles the following files under the MIT License:
|
||||
|
||||
- site
|
||||
Parts of the web site generated by Jekyll (http://jekyllrb.com/)
|
||||
Copyright (c) 2008-2015 Tom Preston-Werner
|
||||
- site/_sass/_font-awesome.scss
|
||||
Font-awesome css files v4.1.0 (http://fortawesome.github.io/Font-Awesome/)
|
||||
Copyright (c) 2013 Dave Gandy
|
||||
- site/_sass/_normalize.scss
|
||||
normalize.css v3.0.2 | git.io/normalize
|
||||
Copyright (c) Nicolas Gallagher and Jonathan Neal
|
||||
- site/_sass/_gridism.scss
|
||||
Gridism: A simple, responsive, and handy CSS grid by @cobyism
|
||||
https://github.com/cobyism/gridism
|
||||
Copyright (c) 2013 Coby Chapple
|
||||
- site/js/html5shiv.min.js
|
||||
HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem
|
||||
- site/js/respond.min.js
|
||||
Respond.js v1.4.2: min/max-width media query polyfill
|
||||
Copyright 2013 Scott Jehl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
The Open Font License
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
The Apache Calcite project bundles the following fonts under the
|
||||
SIL Open Font License (OFL) - http://scripts.sil.org/OFL/
|
||||
|
||||
- site/fonts/fontawesome-webfont.*
|
||||
Font-awesome font files v4.0.3 (http://fortawesome.github.io/Font-Awesome/)
|
|
@ -0,0 +1,5 @@
|
|||
Apache Calcite
|
||||
Copyright 2012-2016 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
|
@ -0,0 +1 @@
|
|||
d0f90841119f1ec02a64ef029ff525171a320cff
|
|
@ -0,0 +1,268 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
APACHE CALCITE SUBCOMPONENTS:
|
||||
|
||||
The Apache Calcite project contains subcomponents with separate copyright
|
||||
notices and license terms. Your use of the source code for the these
|
||||
subcomponents is subject to the terms and conditions of the following
|
||||
licenses.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
The MIT License
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
The Apache Calcite project bundles the following files under the MIT License:
|
||||
|
||||
- site
|
||||
Parts of the web site generated by Jekyll (http://jekyllrb.com/)
|
||||
Copyright (c) 2008-2015 Tom Preston-Werner
|
||||
- site/_sass/_font-awesome.scss
|
||||
Font-awesome css files v4.1.0 (http://fortawesome.github.io/Font-Awesome/)
|
||||
Copyright (c) 2013 Dave Gandy
|
||||
- site/_sass/_normalize.scss
|
||||
normalize.css v3.0.2 | git.io/normalize
|
||||
Copyright (c) Nicolas Gallagher and Jonathan Neal
|
||||
- site/_sass/_gridism.scss
|
||||
Gridism: A simple, responsive, and handy CSS grid by @cobyism
|
||||
https://github.com/cobyism/gridism
|
||||
Copyright (c) 2013 Coby Chapple
|
||||
- site/js/html5shiv.min.js
|
||||
HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem
|
||||
- site/js/respond.min.js
|
||||
Respond.js v1.4.2: min/max-width media query polyfill
|
||||
Copyright 2013 Scott Jehl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
The Open Font License
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
The Apache Calcite project bundles the following fonts under the
|
||||
SIL Open Font License (OFL) - http://scripts.sil.org/OFL/
|
||||
|
||||
- site/fonts/fontawesome-webfont.*
|
||||
Font-awesome font files v4.0.3 (http://fortawesome.github.io/Font-Awesome/)
|
|
@ -0,0 +1,12 @@
|
|||
Apache Calcite
|
||||
Copyright 2012-2017 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
This product is based on source code originally developed
|
||||
by DynamoBI Corporation, LucidEra Inc., SQLstream Inc. and others
|
||||
under the auspices of the Eigenbase Foundation
|
||||
and released as the LucidDB project.
|
||||
|
||||
The web site includes files generated by Jekyll.
|
|
@ -0,0 +1 @@
|
|||
b09e988f64c69c21cc61aa734e9955736a07e016
|
|
@ -0,0 +1,268 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
APACHE CALCITE SUBCOMPONENTS:
|
||||
|
||||
The Apache Calcite project contains subcomponents with separate copyright
|
||||
notices and license terms. Your use of the source code for the these
|
||||
subcomponents is subject to the terms and conditions of the following
|
||||
licenses.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
The MIT License
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
The Apache Calcite project bundles the following files under the MIT License:
|
||||
|
||||
- site
|
||||
Parts of the web site generated by Jekyll (http://jekyllrb.com/)
|
||||
Copyright (c) 2008-2015 Tom Preston-Werner
|
||||
- site/_sass/_font-awesome.scss
|
||||
Font-awesome css files v4.1.0 (http://fortawesome.github.io/Font-Awesome/)
|
||||
Copyright (c) 2013 Dave Gandy
|
||||
- site/_sass/_normalize.scss
|
||||
normalize.css v3.0.2 | git.io/normalize
|
||||
Copyright (c) Nicolas Gallagher and Jonathan Neal
|
||||
- site/_sass/_gridism.scss
|
||||
Gridism: A simple, responsive, and handy CSS grid by @cobyism
|
||||
https://github.com/cobyism/gridism
|
||||
Copyright (c) 2013 Coby Chapple
|
||||
- site/js/html5shiv.min.js
|
||||
HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem
|
||||
- site/js/respond.min.js
|
||||
Respond.js v1.4.2: min/max-width media query polyfill
|
||||
Copyright 2013 Scott Jehl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
The Open Font License
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
The Apache Calcite project bundles the following fonts under the
|
||||
SIL Open Font License (OFL) - http://scripts.sil.org/OFL/
|
||||
|
||||
- site/fonts/fontawesome-webfont.*
|
||||
Font-awesome font files v4.0.3 (http://fortawesome.github.io/Font-Awesome/)
|
|
@ -0,0 +1,12 @@
|
|||
Apache Calcite
|
||||
Copyright 2012-2017 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
This product is based on source code originally developed
|
||||
by DynamoBI Corporation, LucidEra Inc., SQLstream Inc. and others
|
||||
under the auspices of the Eigenbase Foundation
|
||||
and released as the LucidDB project.
|
||||
|
||||
The web site includes files generated by Jekyll.
|
|
@ -0,0 +1 @@
|
|||
b71e76d942b33dfa26e4e3047ff2a774d1f917b4
|
|
@ -0,0 +1,31 @@
|
|||
Janino - An embedded Java[TM] compiler
|
||||
|
||||
Copyright (c) 2001-2016, Arno Unkrig
|
||||
Copyright (c) 2015-2016 TIBCO Software Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
3. Neither the name of JANINO nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,5 @@
|
|||
Janino - An embedded Java[TM] compiler
|
||||
|
||||
Copyright (c) 2001-2016, Arno Unkrig
|
||||
Copyright (c) 2015-2016 TIBCO Software Inc.
|
||||
All rights reserved.
|
|
@ -0,0 +1 @@
|
|||
a941956b3a4664d0cf728ece06ba25cc2110a3aa
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,20 @@
|
|||
eigenbase-properties
|
||||
Copyright (C) 2012-2015, Julian Hyde
|
||||
|
||||
This product includes software from the Eigenbase project, licensed from
|
||||
DynamoBI Corporation.
|
||||
|
||||
Copyright (C) 2005 Dynamo BI Corporation
|
||||
|
||||
===============================================================================
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this software except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1 @@
|
|||
37fde5de7edd5d7ebe075f03f4c083df2ac73dd8
|
|
@ -0,0 +1,31 @@
|
|||
Janino - An embedded Java[TM] compiler
|
||||
|
||||
Copyright (c) 2001-2016, Arno Unkrig
|
||||
Copyright (c) 2015-2016 TIBCO Software Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
3. Neither the name of JANINO nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,5 @@
|
|||
Janino - An embedded Java[TM] compiler
|
||||
|
||||
Copyright (c) 2001-2016, Arno Unkrig
|
||||
Copyright (c) 2015-2016 TIBCO Software Inc.
|
||||
All rights reserved.
|
|
@ -1 +0,0 @@
|
|||
b4261cbabfd2f28b8d4d20d7e3a3d1be48bb890c
|
|
@ -1 +0,0 @@
|
|||
a10732c76bfacdbd633a7eb0f7968b1059a65dfa
|
|
@ -0,0 +1 @@
|
|||
e13484d9da178399d32d2d27ee21a77cfb4b7873
|
|
@ -1 +0,0 @@
|
|||
159a81631ed2cc1bc865f3d8e51239c9e8a20bea
|
|
@ -705,17 +705,29 @@ class DatabaseMetaDataImpl implements DatabaseMetaData {
|
|||
|
||||
@Override
|
||||
public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
|
||||
return this.connectionStatement.executeQuery("select TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS from _TABLES_");
|
||||
String tableCatCheck = "";
|
||||
if(catalog != null) {
|
||||
tableCatCheck = "tableCat = '\" + catalog + \"' and";
|
||||
}
|
||||
if(schemaPattern == null) {
|
||||
schemaPattern = "%";
|
||||
}
|
||||
if(tableNamePattern == null) {
|
||||
tableNamePattern = "%";
|
||||
}
|
||||
return this.connectionStatement.executeQuery("select tableCat, tableSchem, tableName, tableType, remarks from " +
|
||||
"metadata.TABLES where " + tableCatCheck + " tableSchem like '" + schemaPattern + "' and tableName like '" +
|
||||
tableNamePattern + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getSchemas() throws SQLException {
|
||||
return this.connectionStatement.executeQuery("select TABLE_SCHEM, TABLE_CATALOG from _SCHEMAS_");
|
||||
return this.connectionStatement.executeQuery("select distinct tableSchem, tableCat from metadata.TABLES");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getCatalogs() throws SQLException {
|
||||
return this.connectionStatement.executeQuery("select TABLE_CAT from _CATALOGS_");
|
||||
return this.connectionStatement.executeQuery("select distinct tableCat from metadata.TABLES");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -234,6 +234,7 @@ public class FacetStream extends TupleStream implements Expressible {
|
|||
this.zkHost = zkHost;
|
||||
this.params = params;
|
||||
this.buckets = buckets;
|
||||
System.out.println("####### Bucket count:"+buckets.length);
|
||||
this.metrics = metrics;
|
||||
this.bucketSizeLimit = bucketSizeLimit;
|
||||
this.collection = collection;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.apache.solr.client.solrj.io.stream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Array;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -88,6 +89,7 @@ public class JDBCStream extends TupleStream implements Expressible {
|
|||
private ResultSetValueSelector[] valueSelectors;
|
||||
protected ResultSet resultSet;
|
||||
protected transient StreamContext streamContext;
|
||||
protected String sep = Character.toString((char)31);
|
||||
|
||||
public JDBCStream(String connectionUrl, String sqlQuery, StreamComparator definedSort) throws IOException {
|
||||
this(connectionUrl, sqlQuery, definedSort, null, null);
|
||||
|
@ -209,8 +211,8 @@ public class JDBCStream extends TupleStream implements Expressible {
|
|||
try{
|
||||
resultSet = statement.executeQuery(sqlQuery);
|
||||
} catch (SQLException e) {
|
||||
throw new IOException(String.format(Locale.ROOT, "Failed to execute sqlQuery '%s' against JDBC connection '%s'",
|
||||
sqlQuery, connectionUrl), e);
|
||||
throw new IOException(String.format(Locale.ROOT, "Failed to execute sqlQuery '%s' against JDBC connection '%s'.\n"
|
||||
+ e.getMessage(), sqlQuery, connectionUrl), e);
|
||||
}
|
||||
|
||||
try{
|
||||
|
@ -226,18 +228,25 @@ public class JDBCStream extends TupleStream implements Expressible {
|
|||
ResultSetValueSelector[] valueSelectors = new ResultSetValueSelector[metadata.getColumnCount()];
|
||||
|
||||
for(int columnIdx = 0; columnIdx < metadata.getColumnCount(); ++columnIdx){
|
||||
|
||||
final int columnNumber = columnIdx + 1; // cause it starts at 1
|
||||
// Use getColumnLabel instead of getColumnName to make sure fields renamed with AS as picked up properly
|
||||
final String columnName = metadata.getColumnLabel(columnNumber);
|
||||
String className = metadata.getColumnClassName(columnNumber);
|
||||
String typeName = metadata.getColumnTypeName(columnNumber);
|
||||
|
||||
|
||||
if(directSupportedTypes.contains(className)){
|
||||
valueSelectors[columnIdx] = new ResultSetValueSelector() {
|
||||
public Object selectValue(ResultSet resultSet) throws SQLException {
|
||||
Object obj = resultSet.getObject(columnNumber);
|
||||
if(resultSet.wasNull()){ return null; }
|
||||
if(obj instanceof String) {
|
||||
String s = (String)obj;
|
||||
if(s.indexOf(sep) > -1) {
|
||||
s = s.substring(1);
|
||||
return s.split(sep);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
public String getColumnName() {
|
||||
|
@ -277,6 +286,22 @@ public class JDBCStream extends TupleStream implements Expressible {
|
|||
return columnName;
|
||||
}
|
||||
};
|
||||
} else if(Array.class.getName().equals(className)) {
|
||||
valueSelectors[columnIdx] = new ResultSetValueSelector() {
|
||||
public Object selectValue(ResultSet resultSet) throws SQLException {
|
||||
Object o = resultSet.getObject(columnNumber);
|
||||
if(resultSet.wasNull()){ return null; }
|
||||
if(o instanceof Array) {
|
||||
Array array = (Array)o;
|
||||
return array.getArray();
|
||||
} else {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
throw new SQLException(String.format(Locale.ROOT,
|
||||
"Unable to determine the valueSelector for column '%s' (col #%d) of java class '%s' and type '%s'",
|
||||
|
|
|
@ -72,9 +72,7 @@ public class RollupStream extends TupleStream implements Expressible {
|
|||
if(1 != streamExpressions.size()){
|
||||
throw new IOException(String.format(Locale.ROOT,"Invalid expression %s - expecting a single stream but found %d",expression, streamExpressions.size()));
|
||||
}
|
||||
if(0 == metricExpressions.size()){
|
||||
throw new IOException(String.format(Locale.ROOT,"Invalid expression %s - expecting at least 1 metric but found %d",expression, metricExpressions.size()));
|
||||
}
|
||||
|
||||
if(null == overExpression || !(overExpression.getParameter() instanceof StreamExpressionValue)){
|
||||
throw new IOException(String.format(Locale.ROOT,"Invalid expression %s - expecting single 'over' parameter listing fields to rollup by but didn't find one",expression));
|
||||
}
|
||||
|
@ -247,12 +245,14 @@ public class RollupStream extends TupleStream implements Expressible {
|
|||
t = new Tuple(map);
|
||||
}
|
||||
|
||||
currentMetrics = new Metric[metrics.length];
|
||||
currentKey = hashKey;
|
||||
for(int i=0; i<metrics.length; i++) {
|
||||
Metric bucketMetric = metrics[i].newInstance();
|
||||
bucketMetric.update(tuple);
|
||||
currentMetrics[i] = bucketMetric;
|
||||
if (metrics != null) {
|
||||
currentMetrics = new Metric[metrics.length];
|
||||
for(int i=0; i<metrics.length; i++) {
|
||||
Metric bucketMetric = metrics[i].newInstance();
|
||||
bucketMetric.update(tuple);
|
||||
currentMetrics[i] = bucketMetric;
|
||||
}
|
||||
}
|
||||
|
||||
if(t != null) {
|
||||
|
|
|
@ -57,7 +57,6 @@ public class StatsStream extends TupleStream implements Expressible {
|
|||
private SolrParams params;
|
||||
private String collection;
|
||||
private boolean done;
|
||||
private long count;
|
||||
private boolean doCount;
|
||||
protected transient SolrClientCache cache;
|
||||
protected transient CloudSolrClient cloudSolrClient;
|
||||
|
@ -195,8 +194,7 @@ public class StatsStream extends TupleStream implements Expressible {
|
|||
}
|
||||
|
||||
public List<TupleStream> children() {
|
||||
List<TupleStream> l = new ArrayList();
|
||||
return l;
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public void open() throws IOException {
|
||||
|
@ -233,10 +231,9 @@ public class StatsStream extends TupleStream implements Expressible {
|
|||
done = true;
|
||||
return tuple;
|
||||
} else {
|
||||
Map fields = new HashMap();
|
||||
Map<String, Object> fields = new HashMap<>();
|
||||
fields.put("EOF", true);
|
||||
Tuple tuple = new Tuple(fields);
|
||||
return tuple;
|
||||
return new Tuple(fields);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +242,7 @@ public class StatsStream extends TupleStream implements Expressible {
|
|||
}
|
||||
|
||||
private void addStats(ModifiableSolrParams params, Metric[] _metrics) {
|
||||
Map<String, List<String>> m = new HashMap();
|
||||
Map<String, List<String>> m = new HashMap<>();
|
||||
for(Metric metric : _metrics) {
|
||||
String metricId = metric.getIdentifier();
|
||||
if(metricId.contains("(")) {
|
||||
|
@ -255,8 +252,11 @@ public class StatsStream extends TupleStream implements Expressible {
|
|||
String column = parts[1];
|
||||
List<String> stats = m.get(column);
|
||||
|
||||
if(stats == null && !column.equals("*")) {
|
||||
stats = new ArrayList();
|
||||
if(stats == null) {
|
||||
stats = new ArrayList<>();
|
||||
}
|
||||
|
||||
if(!column.equals("*")) {
|
||||
m.put(column, stats);
|
||||
}
|
||||
|
||||
|
@ -290,34 +290,36 @@ public class StatsStream extends TupleStream implements Expressible {
|
|||
|
||||
private Tuple getTuple(NamedList response) {
|
||||
|
||||
Map map = new HashMap();
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
SolrDocumentList solrDocumentList = (SolrDocumentList) response.get("response");
|
||||
|
||||
long count = solrDocumentList.getNumFound();
|
||||
|
||||
if(doCount) {
|
||||
SolrDocumentList solrDocumentList = (SolrDocumentList) response.get("response");
|
||||
this.count = solrDocumentList.getNumFound();
|
||||
map.put("count(*)", this.count);
|
||||
map.put("count(*)", count);
|
||||
}
|
||||
|
||||
NamedList stats = (NamedList)response.get("stats");
|
||||
NamedList statsFields = (NamedList)stats.get("stats_fields");
|
||||
if(count != 0) {
|
||||
NamedList stats = (NamedList)response.get("stats");
|
||||
NamedList statsFields = (NamedList)stats.get("stats_fields");
|
||||
|
||||
for(int i=0; i<statsFields.size(); i++) {
|
||||
String field = statsFields.getName(i);
|
||||
NamedList theStats = (NamedList)statsFields.getVal(i);
|
||||
for(int s=0; s<theStats.size(); s++) {
|
||||
addStat(map, field, theStats.getName(s), theStats.getVal(s));
|
||||
for(int i=0; i<statsFields.size(); i++) {
|
||||
String field = statsFields.getName(i);
|
||||
NamedList theStats = (NamedList)statsFields.getVal(i);
|
||||
for(int s=0; s<theStats.size(); s++) {
|
||||
addStat(map, field, theStats.getName(s), theStats.getVal(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tuple tuple = new Tuple(map);
|
||||
return tuple;
|
||||
return new Tuple(map);
|
||||
}
|
||||
|
||||
public int getCost() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void addStat(Map map, String field, String stat, Object val) {
|
||||
private void addStat(Map<String, Object> map, String field, String stat, Object val) {
|
||||
if(stat.equals("mean")) {
|
||||
map.put("avg("+field+")", val);
|
||||
} else {
|
||||
|
|
|
@ -24,40 +24,50 @@ import org.apache.solr.client.solrj.io.stream.expr.StreamExpressionParameter;
|
|||
import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
|
||||
|
||||
public class CountMetric extends Metric {
|
||||
private String columnName;
|
||||
private long count;
|
||||
|
||||
public CountMetric(){
|
||||
init("count");
|
||||
|
||||
public CountMetric() {
|
||||
this("*");
|
||||
}
|
||||
|
||||
public CountMetric(String columnName) {
|
||||
init("count", columnName);
|
||||
}
|
||||
|
||||
public CountMetric(StreamExpression expression, StreamFactory factory) throws IOException{
|
||||
// grab all parameters out
|
||||
String functionName = expression.getFunctionName();
|
||||
String columnName = factory.getValueOperand(expression, 0);
|
||||
|
||||
// validate expression contains only what we want.
|
||||
if(!"*".equals(columnName)){
|
||||
throw new IOException(String.format(Locale.ROOT,"Invalid expression %s - expected %s(*)", expression, functionName));
|
||||
}
|
||||
|
||||
if(1 != expression.getParameters().size()){
|
||||
throw new IOException(String.format(Locale.ROOT,"Invalid expression %s - unknown operands found", expression));
|
||||
}
|
||||
|
||||
init(functionName);
|
||||
|
||||
|
||||
init(functionName, columnName);
|
||||
}
|
||||
|
||||
public String[] getColumns() {
|
||||
return new String[0];
|
||||
if(isAllColumns()) {
|
||||
return new String[0];
|
||||
}
|
||||
return new String[]{columnName};
|
||||
}
|
||||
|
||||
private void init(String functionName){
|
||||
|
||||
private void init(String functionName, String columnName){
|
||||
this.columnName = columnName;
|
||||
setFunctionName(functionName);
|
||||
setIdentifier(functionName, "(*)");
|
||||
setIdentifier(functionName, "(", columnName, ")");
|
||||
}
|
||||
|
||||
private boolean isAllColumns() {
|
||||
return "*".equals(this.columnName);
|
||||
}
|
||||
|
||||
public void update(Tuple tuple) {
|
||||
++count;
|
||||
if(isAllColumns() || tuple.get(columnName) != null) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
public Long getValue() {
|
||||
|
@ -65,10 +75,11 @@ public class CountMetric extends Metric {
|
|||
}
|
||||
|
||||
public Metric newInstance() {
|
||||
return new CountMetric();
|
||||
return new CountMetric(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamExpressionParameter toExpression(StreamFactory factory) throws IOException {
|
||||
return new StreamExpression(getFunctionName()).withParameter("*");
|
||||
return new StreamExpression(getFunctionName()).withParameter(columnName);
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@
|
|||
positionIncrementGap="0"/>
|
||||
<fieldType name="float" docValues="true" class="solr.TrieFloatField" precisionStep="0" omitNorms="true"
|
||||
positionIncrementGap="0"/>
|
||||
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<fieldType name="long" docValues="true" class="solr.TrieLongField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
|
||||
<fieldType name="tint" class="solr.TrieIntField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
<fieldType name="int" docValues="true" class="solr.TrieIntField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<fieldType name="float" docValues="true" class="solr.TrieFloatField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<fieldType name="long" docValues="true" class="solr.TrieLongField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
|
||||
<fieldType name="tint" class="solr.TrieIntField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
|
||||
|
@ -102,8 +102,8 @@
|
|||
<!-- format for date is 1995-12-31T23:59:59.999Z and only the fractional
|
||||
seconds part (.999) is optional.
|
||||
-->
|
||||
<fieldtype name="date" class="solr.TrieDateField" precisionStep="0"/>
|
||||
<fieldtype name="tdate" class="solr.TrieDateField" precisionStep="6"/>
|
||||
<fieldtype name="date" class="solr.TrieDateField" precisionStep="0" docValues="true"/>
|
||||
<fieldtype name="tdate" class="solr.TrieDateField" precisionStep="6" docValues="true"/>
|
||||
|
||||
|
||||
<!-- solr.TextField allows the specification of custom
|
||||
|
|
|
@ -26,17 +26,25 @@ import java.sql.SQLException;
|
|||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
import org.apache.lucene.util.LuceneTestCase.Slow;
|
||||
import org.apache.solr.client.solrj.impl.CloudSolrClient;
|
||||
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
|
||||
import org.apache.solr.client.solrj.request.UpdateRequest;
|
||||
import org.apache.solr.cloud.AbstractDistribZkTestBase;
|
||||
import org.apache.solr.cloud.SolrCloudTestCase;
|
||||
import org.apache.solr.common.cloud.Aliases;
|
||||
import org.apache.solr.common.cloud.ZkStateReader;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -203,21 +211,21 @@ public class JdbcTest extends SolrCloudTestCase {
|
|||
|
||||
assertEquals("hello3", rs.getString("a_s"));
|
||||
assertEquals("hello3", rs.getString(1));
|
||||
assertEquals(26, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(26, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(26, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello0", rs.getString("a_s"));
|
||||
assertEquals("hello0", rs.getString(1));
|
||||
assertEquals(18, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(18, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(18, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello4", rs.getString("a_s"));
|
||||
assertEquals("hello4", rs.getString(1));
|
||||
assertEquals(11, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(11, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(11, rs.getDouble(2), 0);
|
||||
|
||||
assertFalse(rs.next());
|
||||
|
@ -243,21 +251,21 @@ public class JdbcTest extends SolrCloudTestCase {
|
|||
|
||||
assertEquals("hello3", rs.getString("a_s"));
|
||||
assertEquals("hello3", rs.getString(1));
|
||||
assertEquals(26, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(26, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(26, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello0", rs.getString("a_s"));
|
||||
assertEquals("hello0", rs.getString(1));
|
||||
assertEquals(18, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(18, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(18, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello4", rs.getString("a_s"));
|
||||
assertEquals("hello4", rs.getString(1));
|
||||
assertEquals(11, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(11, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(11, rs.getDouble(2), 0);
|
||||
|
||||
assertFalse(rs.next());
|
||||
|
@ -287,21 +295,21 @@ public class JdbcTest extends SolrCloudTestCase {
|
|||
|
||||
assertEquals("hello3", rs.getString("a_s"));
|
||||
assertEquals("hello3", rs.getString(1));
|
||||
assertEquals(26, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(26, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(26, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello0", rs.getString("a_s"));
|
||||
assertEquals("hello0", rs.getString(1));
|
||||
assertEquals(18, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(18, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(18, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello4", rs.getString("a_s"));
|
||||
assertEquals("hello4", rs.getString(1));
|
||||
assertEquals(11, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(11, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(11, rs.getDouble(2), 0);
|
||||
|
||||
assertFalse(rs.next());
|
||||
|
@ -332,21 +340,21 @@ public class JdbcTest extends SolrCloudTestCase {
|
|||
|
||||
assertEquals("hello3", rs.getString("a_s"));
|
||||
assertEquals("hello3", rs.getString(1));
|
||||
assertEquals(26, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(26, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(26, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello0", rs.getString("a_s"));
|
||||
assertEquals("hello0", rs.getString(1));
|
||||
assertEquals(18, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(18, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(18, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello4", rs.getString("a_s"));
|
||||
assertEquals("hello4", rs.getString(1));
|
||||
assertEquals(11, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(11, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(11, rs.getDouble(2), 0);
|
||||
|
||||
assertFalse(rs.next());
|
||||
|
@ -382,21 +390,21 @@ public class JdbcTest extends SolrCloudTestCase {
|
|||
|
||||
assertEquals("hello3", rs.getString("a_s"));
|
||||
assertEquals("hello3", rs.getString(1));
|
||||
assertEquals(26, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(26, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(26, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello0", rs.getString("a_s"));
|
||||
assertEquals("hello0", rs.getString(1));
|
||||
assertEquals(18, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(18, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(18, rs.getDouble(2), 0);
|
||||
|
||||
assertTrue(rs.next());
|
||||
|
||||
assertEquals("hello4", rs.getString("a_s"));
|
||||
assertEquals("hello4", rs.getString(1));
|
||||
assertEquals(11, rs.getDouble("sum(a_f)"), 0);
|
||||
assertEquals(11, rs.getDouble("EXPR$1"), 0); //sum(a_f)
|
||||
assertEquals(11, rs.getDouble(2), 0);
|
||||
|
||||
assertFalse(rs.next());
|
||||
|
@ -405,6 +413,7 @@ public class JdbcTest extends SolrCloudTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Ignore("Fix error checking")
|
||||
@Test
|
||||
public void testErrorPropagation() throws Exception {
|
||||
//Test error propagation
|
||||
|
@ -496,28 +505,53 @@ public class JdbcTest extends SolrCloudTestCase {
|
|||
// assertEquals(0, databaseMetaData.getDriverMajorVersion());
|
||||
// assertEquals(0, databaseMetaData.getDriverMinorVersion());
|
||||
|
||||
|
||||
List<String> tableSchemas = new ArrayList<>(Arrays.asList(zkHost, "metadata"));
|
||||
try(ResultSet rs = databaseMetaData.getSchemas()) {
|
||||
assertTrue(rs.next());
|
||||
assertTrue(tableSchemas.contains(rs.getString("tableSchem")));
|
||||
tableSchemas.remove(rs.getString("tableSchem"));
|
||||
assertNull(rs.getString("tableCat"));
|
||||
assertTrue(rs.next());
|
||||
assertTrue(tableSchemas.contains(rs.getString("tableSchem")));
|
||||
tableSchemas.remove(rs.getString("tableSchem"));
|
||||
assertNull(rs.getString("tableCat"));
|
||||
assertFalse(rs.next());
|
||||
assertTrue(tableSchemas.isEmpty());
|
||||
}
|
||||
|
||||
try(ResultSet rs = databaseMetaData.getCatalogs()) {
|
||||
assertTrue(rs.next());
|
||||
assertEquals(zkHost, rs.getString("TABLE_CAT"));
|
||||
assertNull(rs.getString("tableCat"));
|
||||
assertFalse(rs.next());
|
||||
}
|
||||
|
||||
List<String> collections = new ArrayList<>();
|
||||
collections.addAll(cluster.getSolrClient().getZkStateReader().getClusterState().getCollectionsMap().keySet());
|
||||
Collections.sort(collections);
|
||||
CloudSolrClient solrClient = cluster.getSolrClient();
|
||||
solrClient.connect();
|
||||
ZkStateReader zkStateReader = solrClient.getZkStateReader();
|
||||
|
||||
try(ResultSet rs = databaseMetaData.getSchemas()) {
|
||||
assertFalse(rs.next());
|
||||
SortedSet<String> tables = new TreeSet<>();
|
||||
|
||||
Set<String> collectionsSet = zkStateReader.getClusterState().getCollectionsMap().keySet();
|
||||
tables.addAll(collectionsSet);
|
||||
|
||||
Aliases aliases = zkStateReader.getAliases();
|
||||
if(aliases != null) {
|
||||
Map<String, String> collectionAliasMap = aliases.getCollectionAliasMap();
|
||||
if(collectionAliasMap != null) {
|
||||
Set<String> aliasesSet = collectionAliasMap.keySet();
|
||||
tables.addAll(aliasesSet);
|
||||
}
|
||||
}
|
||||
|
||||
try(ResultSet rs = databaseMetaData.getTables(zkHost, null, "%", null)) {
|
||||
for(String acollection : collections) {
|
||||
try(ResultSet rs = databaseMetaData.getTables(null, zkHost, "%", null)) {
|
||||
for(String table : tables) {
|
||||
assertTrue(rs.next());
|
||||
assertEquals(zkHost, rs.getString("TABLE_CAT"));
|
||||
assertNull(rs.getString("TABLE_SCHEM"));
|
||||
assertEquals(acollection, rs.getString("TABLE_NAME"));
|
||||
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
|
||||
assertNull(rs.getString("REMARKS"));
|
||||
assertNull(rs.getString("tableCat"));
|
||||
assertEquals(zkHost, rs.getString("tableSchem"));
|
||||
assertEquals(table, rs.getString("tableName"));
|
||||
assertEquals("TABLE", rs.getString("tableType"));
|
||||
assertNull(rs.getString("remarks"));
|
||||
}
|
||||
assertFalse(rs.next());
|
||||
}
|
||||
|
|
|
@ -917,7 +917,6 @@ public class StreamExpressionTest extends SolrCloudTestCase {
|
|||
t = tuples.get(1);
|
||||
assertTrue(t.getString("id").equals("9"));
|
||||
|
||||
|
||||
stream = factory.constructStream("having(rollup(over=a_f, sum(a_i), search(" + COLLECTIONORALIAS + ", q=*:*, fl=\"id,a_s,a_i,a_f\", sort=\"a_f asc\")), and(eq(sum(a_i), 9),eq(sum(a_i), 9)))");
|
||||
context = new StreamContext();
|
||||
context.setSolrClientCache(solrClientCache);
|
||||
|
@ -1038,8 +1037,6 @@ public class StreamExpressionTest extends SolrCloudTestCase {
|
|||
t = tuples.get(0);
|
||||
assertTrue(t.getDouble("a_f") == 10.0D);
|
||||
|
||||
|
||||
|
||||
solrClientCache.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -1508,6 +1508,23 @@ public void testTrace() throws Exception {
|
|||
assertEquals(5.5, avgf.doubleValue(), 0.01);
|
||||
assertEquals(2, count.doubleValue(), 0.01);
|
||||
|
||||
// Test will null metrics
|
||||
rollupStream = new RollupStream(stream, buckets, metrics);
|
||||
tuples = getTuples(rollupStream);
|
||||
|
||||
assert(tuples.size() == 3);
|
||||
tuple = tuples.get(0);
|
||||
bucket = tuple.getString("a_s");
|
||||
assertTrue(bucket.equals("hello0"));
|
||||
|
||||
tuple = tuples.get(1);
|
||||
bucket = tuple.getString("a_s");
|
||||
assertTrue(bucket.equals("hello3"));
|
||||
|
||||
tuple = tuples.get(2);
|
||||
bucket = tuple.getString("a_s");
|
||||
assertTrue(bucket.equals("hello4"));
|
||||
|
||||
|
||||
//Test will null value in the grouping field
|
||||
new UpdateRequest()
|
||||
|
|
Loading…
Reference in New Issue