blob: 2a43797cf42b8503b65d4192b8a0e8da75284d79 [file] [log] [blame]
/*
* 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.drill.exec.store.mapr.db.json;
import org.apache.commons.codec.binary.Base64;
import org.apache.drill.common.expression.FunctionCall;
import org.apache.drill.common.expression.LogicalExpression;
import org.apache.drill.common.expression.SchemaPath;
import org.apache.drill.common.expression.ValueExpressions.IntExpression;
import org.apache.drill.common.expression.ValueExpressions.LongExpression;
import org.apache.drill.common.expression.ValueExpressions.QuotedString;
import org.apache.drill.common.expression.visitors.AbstractExprVisitor;
import com.google.common.collect.ImmutableMap;
import org.ojai.Value;
import org.ojai.store.QueryCondition;
import com.mapr.db.impl.ConditionImpl;
import com.mapr.db.impl.MapRDBImpl;
import java.nio.ByteBuffer;
class OjaiFunctionsProcessor extends AbstractExprVisitor<Void, Void, RuntimeException> {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(OjaiFunctionsProcessor.class);
private QueryCondition queryCond;
private OjaiFunctionsProcessor() {
}
private static String getStackTrace() {
final Throwable throwable = new Throwable();
final StackTraceElement[] ste = throwable.getStackTrace();
final StringBuilder sb = new StringBuilder();
for (int i = 1; i < ste.length; ++i) {
sb.append(ste[i].toString());
sb.append('\n');
}
return sb.toString();
}
@Override
public Void visitUnknown(LogicalExpression e, Void valueArg) throws RuntimeException {
logger.debug("visitUnknown() e class " + e.getClass());
logger.debug(getStackTrace());
return null;
}
private static class Ref<T> {
T value;
}
private static SchemaPath getSchemaPathArg(LogicalExpression expr) {
final Ref<SchemaPath> ref = new Ref<>();
expr.accept(new OjaiFunctionsProcessor() {
@Override
public Void visitSchemaPath(SchemaPath e, Void v) {
ref.value = e;
return null;
}
}, null);
return ref.value;
}
private static String getStringArg(LogicalExpression expr) {
final Ref<QuotedString> ref = new Ref<>();
expr.accept(new OjaiFunctionsProcessor() {
@Override
public Void visitQuotedStringConstant(QuotedString e, Void v) {
ref.value = e;
return null;
}
}, null);
return ref.value != null ? ref.value.getString() : null;
}
private static int getIntArg(LogicalExpression expr) {
final Ref<Integer> ref = new Ref<>();
expr.accept(new OjaiFunctionsProcessor() {
@Override
public Void visitIntConstant(IntExpression e, Void v) {
ref.value = new Integer(e.getInt());
return null;
}
}, null);
return ref.value != null ? ref.value.intValue() : 0;
}
private static long getLongArg(LogicalExpression expr) {
final Ref<Long> ref = new Ref<>();
expr.accept(new OjaiFunctionsProcessor() {
@Override
public Void visitIntConstant(IntExpression e, Void v) {
ref.value = new Long(e.getInt());
return null;
}
@Override
public Void visitLongConstant(LongExpression e, Void v) {
ref.value = e.getLong();
return null;
}
}, null);
return ref.value != null ? ref.value.longValue() : 0;
}
private final static ImmutableMap<String, QueryCondition.Op> STRING_TO_RELOP;
static {
ImmutableMap.Builder<String, QueryCondition.Op> builder = ImmutableMap.builder();
STRING_TO_RELOP = builder
.put("=", QueryCondition.Op.EQUAL)
.put("<>", QueryCondition.Op.NOT_EQUAL)
.put("<", QueryCondition.Op.LESS)
.put("<=", QueryCondition.Op.LESS_OR_EQUAL)
.put(">", QueryCondition.Op.GREATER)
.put(">=", QueryCondition.Op.GREATER_OR_EQUAL)
.build();
}
@Override
public Void visitFunctionCall(FunctionCall call, Void v) throws RuntimeException {
final String functionName = call.getName();
final String fieldName = FieldPathHelper.schemaPath2FieldPath(getSchemaPathArg(call.arg(0))).asPathString();
switch(functionName) {
case "ojai_sizeof": {
// ojai_sizeof(field, "<rel-op>", <int-value>)
final String relOp = getStringArg(call.arg(1));
final long size = getLongArg(call.arg(2));
queryCond = MapRDBImpl.newCondition()
.sizeOf(fieldName, STRING_TO_RELOP.get(relOp), size)
.build();
break;
}
case "ojai_typeof":
case "ojai_nottypeof": {
// ojai_[not]typeof(field, <type-code>);
final int typeCode = getIntArg(call.arg(1));
final Value.Type typeValue = Value.Type.valueOf(typeCode);
queryCond = MapRDBImpl.newCondition();
if (functionName.equals("ojai_typeof")) {
queryCond.typeOf(fieldName, typeValue);
} else {
queryCond.notTypeOf(fieldName, typeValue);
}
queryCond.build();
break;
}
case "ojai_matches":
case "ojai_notmatches": {
// ojai_[not]matches(field, <regex>);
final String regex = getStringArg(call.arg(1));
if (functionName.equals("ojai_matches")) {
queryCond = MapRDBImpl.newCondition()
.matches(fieldName, regex);
} else {
queryCond = MapRDBImpl.newCondition()
.notMatches(fieldName, regex);
}
queryCond.build();
break;
}
case "ojai_condition": {
// ojai_condition(field, <serialized-condition>);
final String condString = getStringArg(call.arg(1));
final byte[] condBytes = Base64.decodeBase64(condString);
final ByteBuffer condBuffer = ByteBuffer.wrap(condBytes);
queryCond = ConditionImpl.parseFrom(condBuffer);
break;
}
default:
throw new IllegalArgumentException("unrecognized functionName " + functionName);
} // switch(functionName)
return null;
}
public static OjaiFunctionsProcessor process(FunctionCall call) {
final OjaiFunctionsProcessor processor = new OjaiFunctionsProcessor();
call.accept(processor, null);
return processor;
}
public QueryCondition getCondition() {
return queryCond;
}
}