Merge branch 'jira/solr-8593'

This commit is contained in:
Joel Bernstein 2017-02-15 13:55:09 -05:00
commit bfeb4e7f84
53 changed files with 4483 additions and 2525 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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());
}
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -0,0 +1 @@
c16b346eef02495f2f4b429fe04c33e526ec0229

View File

@ -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/)

View File

@ -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/).

View File

@ -0,0 +1 @@
d0f90841119f1ec02a64ef029ff525171a320cff

View File

@ -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/)

View File

@ -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.

View File

@ -0,0 +1 @@
b09e988f64c69c21cc61aa734e9955736a07e016

View File

@ -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/)

View File

@ -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.

View File

@ -0,0 +1 @@
b71e76d942b33dfa26e4e3047ff2a774d1f917b4

View File

@ -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.

View File

@ -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.

View File

@ -0,0 +1 @@
a941956b3a4664d0cf728ece06ba25cc2110a3aa

View File

@ -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.

View File

@ -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.

View File

@ -0,0 +1 @@
37fde5de7edd5d7ebe075f03f4c083df2ac73dd8

View File

@ -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.

View File

@ -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.

View File

@ -1 +0,0 @@
b4261cbabfd2f28b8d4d20d7e3a3d1be48bb890c

View File

@ -1 +0,0 @@
a10732c76bfacdbd633a7eb0f7968b1059a65dfa

View File

@ -0,0 +1 @@
e13484d9da178399d32d2d27ee21a77cfb4b7873

View File

@ -1 +0,0 @@
159a81631ed2cc1bc865f3d8e51239c9e8a20bea

View File

@ -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

View File

@ -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;

View File

@ -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'",

View File

@ -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) {

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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"/>

View File

@ -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

View File

@ -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());
}

View File

@ -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();
}

View File

@ -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()